简体   繁体   English

调用时指定默认参数 C++ function

[英]Specifying default parameter when calling C++ function

Suppose I have code like this:假设我有这样的代码:

void f(int a = 0, int b = 0, int c = 0)
{
    //...Some Code...
}

As you can evidently see above with my code, the parameters a , b , and c have default parameter values of 0. Now take a look at my main function below:正如您在上面的代码中明显看到的那样,参数abc的默认参数值为 0。现在看看我下面的主要 function :

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.
}

Now I know that I can't just skip a parameter, and let it have the default value, because that value would evaluate as the parameter at that position.现在我知道我不能只跳过一个参数,让它具有默认值,因为该值将评估为 position 的参数。 What I mean is, that I cannot, say call, f(a,c) , because, c would be evaluated as b , which is what I don't want, especially if c is the wrong type.我的意思是,我不能说调用f(a,c) ,因为c将被评估为b ,这是我不想要的,特别是如果c是错误的类型。 Is there a way for the calling function to specify in C++, to use whatever default parameter value there is for the function in any given position, without being limited to going backwards from the last parameter to none? Is there a way for the calling function to specify in C++, to use whatever default parameter value there is for the function in any given position, without being limited to going backwards from the last parameter to none? Is there any reserved keyword to achieve this, or at least a work-around?是否有任何保留关键字来实现这一点,或者至少是一种解决方法? An example I can give would be like:我可以举一个例子:

f(a, def, c) //Where def would mean default.

There isn't a reserved word for this, and f(a,,c) is not valid either.没有为此保留字,并且f(a,,c)也无效。 You can omit a number of rightmost optional parameters, as you show, but not the middle one like that.如您所示,您可以省略一些最右边的可选参数,但不能像那样省略中间的参数。

http://www.learncpp.com/cpp-tutorial/77-default-parameters/ http://www.learncpp.com/cpp-tutorial/77-default-parameters/

Quoting directly from the link above:直接从上面的链接引用:

Multiple default parameters多个默认参数

A function can have multiple default parameters:一个函数可以有多个默认参数:

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

Given the following function calls:鉴于以下函数调用:

 printValues(1, 2, 3); printValues(1, 2); printValues(1); printValues();

The following output is produced:产生以下输出:

 Values: 1 2 3 Values: 1 2 30 Values: 1 20 30 Values: 10 20 30

Note that it is impossible to supply a user-defined value for z without also supplying a value for x and y.请注意,如果不提供 x 和 y 的值,就不可能为 z 提供用户定义的值。 This is because C++ does not support a function call syntax such as printValues(,,3).这是因为 C++ 不支持函数调用语法,例如 printValues(,,3)。 This has two major consequences:这有两个主要后果:

1) All default parameters must be the rightmost parameters. 1) 所有默认参数必须是最右边的参数。 The following is not allowed:不允许出现以下情况:

 void printValue(int x=10, int y); // not allowed

2) If more than one default parameter exists, the leftmost default parameter should be the one most likely to be explicitly set by the user. 2) 如果存在多个默认参数,则最左边的默认参数应该是最有可能被用户明确设置的一个。

As workaround, you may (ab)use boost::optional (until std::optional from c++17):作为解决方法,您可以(ab)使用boost::optional (直到 c++17 中的std::optional ):

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...
}

and then call it然后调用它

f(a, boost::none, c);

Not exactly what you asked for, but you can use std::bind() to fix a value for a parameter.不完全是您所要求的,但您可以使用std::bind()来修复参数的值。

Something like就像是

#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;
}

With std::bind() you can fix values different from default parameters' values or values for parameters without default values.使用std::bind()可以修复与默认参数值不同的值或没有默认值的参数值。

Take into account that std::bind() is available only from C++11.考虑到std::bind()仅在 C++11 中可用。

If all parameters of the function were of distinct types, you could find out which parameters were passed and which were not and choose the default value for the latter.如果函数的所有参数都是不同类型的,您可以找出哪些参数被传递,哪些没有,并为后者选择默认值。

In order to achieve the distinct type requirement, you can wrap your parameters and pass it to a variadic function template.为了实现不同的类型要求,您可以包装参数并将其传递给可变参数函数模板。 Then even the order of the argument does not matter anymore:那么即使是参数的顺序也不再重要:

#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();
}

output输出

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

live example活生生的例子

You already have an accepted answer, but here's another workaround (that - I believe - has advantages over the other proposed workarounds):您已经有一个可接受的答案,但这是另一种解决方法(我相信它比其他建议的解决方法具有优势):

You can strong-type the arguments:您可以强类型参数:

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);
}

Advantages:优点:

  • it's simple and easy to maintain (one line per argument).它简单且易于维护(每个参数一行)。
  • provides a natural point for constricting the API further (for example, "throw if B's value is negative").为进一步限制 API 提供了一个自然点(例如,“如果 B 的值为负,则抛出”)。
  • it doesn't get in the way (works with default construction, works with intellisense/auto-complete/whatever as good as any other class)它不会妨碍(适用于默认构造,适用于智能感知/自动完成/与任何其他类一样好)
  • it is self-documenting.它是自我记录的。
  • it's as fast as the native version.它和原生版本一样快。

Disadvantages:缺点:

  • increases name pollution (better put all this in a namespace).增加名称污染(最好将所有这些都放在一个名称空间中)。
  • while simple, it is still more code to maintain (than just defining the function directly).虽然简单,但仍然需要维护更多的代码(而不是直接定义函数)。
  • it may raise a few eyebrows (consider adding a comment on why strong-typing is needed)它可能会引起一些关注(考虑添加关于为什么需要强类型的评论)

I will just use static functions to define default values that can change:我将只使用 static 函数来定义可以更改的默认值:

class defValsExample 
{
public: 
    defValsExample() {
    }

    static int f1def_a() { return 1; }
    static int f1def_b() { return 2; }

    int f1(int a = f1def_a(), int b = f1def_b()) {
        return a+b;
    }
};

int main()
{
    defValsExample t; 

    int c = t.f1(t.f1def_a(),4);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM