Предположим, у меня есть такой код:
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
Как вы можете видеть выше с моим кодом, параметры a
,b
, а также c
имеют значения параметров по умолчанию 0. Теперь взгляните на мою основную функцию ниже:
int main()
{
//Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
//note the above parameters could be changed for the other variables
//as well.
}
Теперь я знаю, что не могу просто пропустить параметр и дать ему значение по умолчанию, потому что это значение будет оцениваться как параметр в этой позиции. Я имею в виду, что я не могу, скажем, позвонить, f(a,c)
, так как, c
будет оцениваться как b
что я не хочу, особенно если c
это неправильный тип. Есть ли способ для вызывающей функции указать в C ++, чтобы использовать любое значение параметра по умолчанию для функции в любой заданной позиции, не ограничиваясь переходом от последнего параметра к нулю? Есть ли зарезервированное ключевое слово для достижения этого или хотя бы обходной путь? Пример, который я могу привести:
f(a, def, c) //Where def would mean default.
В качестве обходного пути вы можете (ab) использовать boost::optional
(до тех пор std::optional
из с ++ 17):
void f(boost::optional<int> oa = boost::none,
boost::optional<int> ob = boost::none,
boost::optional<int> oc = boost::none)
{
int a = oa.value_or(0); // Real default value go here
int b = ob.value_or(0); // Real default value go here
int c = oc.value_or(0); // Real default value go here
//...Some Code...
}
а потом позвони
f(a, boost::none, c);
Для этого нет зарезервированного слова, и f(a,,c)
тоже недействительно. Вы можете опустить ряд крайних правых необязательных параметров, как показано, но не средний, как этот.
http://www.learncpp.com/cpp-tutorial/77-default-parameters/
Цитирование непосредственно по ссылке выше:
Несколько параметров по умолчанию
Функция может иметь несколько параметров по умолчанию:
void printValues(int x=10, int y=20, int z=30) { std::cout << "Values: " << x << " " << y << " " << z << '\n'; }
Учитывая следующие вызовы функций:
printValues(1, 2, 3); printValues(1, 2); printValues(1); printValues();
Получается следующий вывод:
Values: 1 2 3 Values: 1 2 30 Values: 1 20 30 Values: 10 20 30
Обратите внимание, что невозможно указать пользовательское значение для z
без предоставления значения для х и у. Это потому что C ++ делает
не поддерживает синтаксис вызова функции, такой как printValues (,, 3). Это имеет
два основных последствия:1) Все параметры по умолчанию должны быть самыми правыми параметрами.
не допускается следующее:void printValue(int x=10, int y); // not allowed
2) Если существует более одного параметра по умолчанию, самый левый по умолчанию
параметр должен быть наиболее вероятным для явного
пользователь.
Не совсем то, что вы спрашиваете, но вы можете использовать std::bind()
установить значение для параметра.
Что-то вроде
#include <functional>
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
int main()
{
//Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
//note the above parameters could be changed for the other variables
//as well.
using namespace std::placeholders; // for _1, _2
auto f1 = std::bind(f, _1, 0, _2);
f1(a, c); // call f(a, 0, c);
return 0;
}
С std::bind()
Вы можете исправить значения, отличные от значений параметров по умолчанию или значений параметров без значений по умолчанию.
Взять хотя бы то, что std::bind()
доступно только из C ++ 11.
p.s .: извините за мой плохой английский.
Если бы все параметры функции были отчетливый типы, вы можете узнать, какие параметры были переданы, а какие нет, и выбрать значение по умолчанию для последних.
Для достижения четкого требования к типу вы можете обернуть ваши параметры и передать их в шаблон функции с переменным числом аргументов.
Тогда даже порядок аргументов больше не имеет значения:
#include <tuple>
#include <iostream>
#include <type_traits>
// -----
// from http://stackoverflow.com/a/25958302/678093
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template <typename T, typename Tuple>
using tuple_contains_type = typename has_type<T, Tuple>::type;
//------template <typename Tag, typename T, T def>
struct Value{
Value() : v(def){}
Value(T v) : v(v){}
T v;
};
using A = Value<struct A_, int, 1>;
using B = Value<struct B_, int, 2>;
using C = Value<struct C_, int, 3>;template <typename T, typename Tuple>
std::enable_if_t<tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple t)
{
return std::get<T>(t);
}
template <typename T, typename Tuple>
std::enable_if_t<!tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple)
{
return T{};
}
template <typename InputTuple, typename... Params>
auto getValueOrDefault(std::tuple<Params...>, InputTuple t)
{
return std::make_tuple(getValueOrDefaultImpl<Params>(t)...);
}
template <typename... Params, typename ArgTuple>
auto getParams(ArgTuple argTuple)
{
using ParamTuple = std::tuple<Params...>;
ParamTuple allValues = getValueOrDefault(ParamTuple{}, argTuple);
return allValues;
}
template <typename... Args>
void f(Args ... args)
{
auto allParams = getParams<A,B,C>(std::make_tuple(args...));
std::cout << "a = " << std::get<A>(allParams).v << " b = " << std::get<B>(allParams).v << " c = " << std::get<C>(allParams).v << std::endl;
}
int main()
{
A a{10};
B b{100};
C c{1000};
f(a, b, c);
f(b, c, a);
f(a, b);
f(a);
f();
}
выход
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 3
a = 10 b = 2 c = 3
a = 1 b = 2 c = 3
редактировать: этот вопрос был старше, и я нашел его, когда другой вопрос был закрыт как дубликат (для плагиата).
У вас уже есть принятый ответ, но вот еще один обходной путь (который, я считаю, имеет преимущества по сравнению с другими предлагаемыми обходными путями):
Вы можете строго набрать аргументы:
struct A { int value = 0; };
struct B { int value = 2; };
struct C { int value = 4; };
void f(A a = {}, B b = {}, C c = {}) {}
void f(A a, C c) {}
int main()
{
auto a = 0;
auto b = -5;
auto c = 1;
f(a, b, c);
f(a, C{2});
f({}, {}, 3);
}
Преимущества:
Недостатки: