C++ 在调用C++;功能

C++ 在调用C++;功能,c++,c++11,default-value,language-construct,C++,C++11,Default Value,Language Construct,假设我有这样的代码: 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);

假设我有这样的代码:

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.

此项没有保留字,
f(a,c)
也无效。如图所示,您可以省略一些最右边的可选参数,但中间的参数则不能省略

直接从上面的链接引用:

多个默认参数

一个函数可以有多个默认参数:

void printValues(int x=10, int y=20, int z=30)
{
    std::cout << "Values: " << x << " " << y << " " << z << '\n';
}
产生以下输出:

Values: 1 2 3
Values: 1 2 30
Values: 1 20 30
Values: 10 20 30
请注意,不可能为z提供用户定义的值 也不提供x和y的值。这是因为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;
}
#包括
空f(整数a=0,整数b=0,整数c=0)
{
//…一些代码。。。
}
int main()
{
//以下是调用上述函数的4种方法:
INTA=2;
int b=3;
int c=-1;
f(a、b、c);
f(a,b);
f(a);
f();
//注:上述参数可针对其他变量进行更改
//还有。
使用命名空间std::占位符;//对于_1,_2
自动f1=std::bind(f,_1,0,_2);
f1(a,c);//调用f(a,0,c);
返回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();
}

作为解决方法,您可以(ab)使用
boost::optional
(直到c++17中的
std::optional
):


编辑:这个问题比较老,我是在另一个问题作为重复问题关闭时发现的(因为剽窃)

您已经有了一个公认的答案,但这里有另一个解决方案(我相信,它比其他建议的解决方案有优势):

您可以强类型输入参数:

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);
}
优点:

  • 它简单且易于维护(每个参数一行)
  • 为进一步压缩API提供了一个自然点(例如,“如果B的值为负值则抛出”)
  • 它不会妨碍(使用默认构造,使用intellisense/auto complete/任何与任何其他类一样好的类)
  • 这是自我记录
  • 它和本地版本一样快
缺点:

  • 增加名称污染(最好将所有这些放在名称空间中)
  • 虽然很简单,但仍需要维护更多的代码(而不仅仅是直接定义函数)
  • 它可能会引起一些注意(考虑添加一条注释,说明为什么需要强输入)

我已经看过你的链接,但我已经知道你现在说了什么。谢谢你的意见,如果没有更好的答案,我会把它标记为正确的。好的。如果你相信它所说的,那么你的问题就会得到回答。你需要构建你的功能来实现你想要的行为。例如,如果用户输入了一些无效值,可能是-1,那么就让它使用默认值。谢谢您的解决方法。实际上我可能会用这个+1@ArnavBorborah-不客气;在你的评论下修改了我的回答;希望能有帮助。谢谢你的回答,但是可变模板+无论如何,谢谢你的邀请link@ArnavBorborah可变模板有什么问题?省略号不安全吗?@arnavborah在哪方面不安全?顺便说一句:一个可变模板和一个C省略号不一样。好吧,我把它们弄糊涂了,另一个堆栈溢出的答案,提到C省略号是危险的。你可以看看命名参数。将C++中的这个特性作为BooStIdPosialPosil函数有几个技巧,然后指定您给出的参数。如果看起来像这样做,可能会有设计缺陷。我建议你重新评估一下。@RobK这只是一个好奇的问题。这是一个很好的最佳解决方案。我真的很喜欢这个,可能会用到它+1.
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
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);
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);
}