c++默认参数:是否可以在不覆盖早期默认参数的情况下覆盖默认参数

c++ Default paramaters: is it possible to override a default parameter without overriding earlier default parameters

本文关键字:默认 参数 覆盖 情况下 是否 c++      更新时间:2023-10-16

我有一个函数:

int function(int a, int b = 1, int c = 2){
    return a+b+c;
}

我想将"c"变量的值设置为3,但不想设置"b"的值

在python这样的语言中,我可以做到这一点:

function(23,c=3)

然而,在c++中,我找不到这样的方法。我能找到的所有例子都涉及在"c"的值之前设置"b"的值,比如:

function(23,1,3);

如何直接设置默认参数的值?

这在C++中是不可能的(至少不能直接实现)。您可以提供所有参数,直到最后一个要提供的参数为止,并按照声明给出的顺序。

在C++中不能做到这一点。

作为一种变通方法,您可以将所有参数包装为类(或结构)中具有默认值的字段。然后,您可以为该类设置多个构造函数,这些构造函数只允许您设置那些您真正感兴趣的字段,以便相对于默认值进行更改。

它在c++中是可能的。。。如果你愿意跳过重重关卡。

有趣的是,这里有一个如何做到这一点的例子:

#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
//
// utility to check whether a type is in a list of types
//
template<class T, class...Ts> struct is_in;
template<class T, class U>
struct is_in<T, U>
: std::is_same<T, U>::type {};
template<class T, class U, class...Rest>
struct is_in<T, U, Rest...>
: std::integral_constant<bool, std::is_same<T, U>::value || is_in<T, Rest...>::value>
{};
//
// a wrapper around fundamental types so we can 'name' types
//
template<class Type, class Tag>
struct fundamental {
    using value_type = Type;
    using tag_type = Tag;
    fundamental(Type x) : _x(x) {}
    operator const Type&() const { return _x; }
    operator Type&() { return _x; }
    Type _x;
};
//
// a utility to figure out a fundamental type's value or to take it's default value if it's not present
//
template<class Fundamental, class Tuple, typename = void>
struct value_of_impl
{
    static typename Fundamental::value_type apply(const Tuple& t)
    {
        return Fundamental::tag_type::dflt;
    }
};
template<class Fundamental, class...Types>
struct value_of_impl<Fundamental, std::tuple<Types...>, std::enable_if_t<is_in<Fundamental, Types...>::value>>
{
    static typename Fundamental::value_type apply(const std::tuple<Types...>& t)
    {
        return typename Fundamental::value_type(std::get<Fundamental>(t));
    }
};
template<class Fundamental, class Tuple>
decltype(auto) value_of(const Tuple& t)
{
    return value_of_impl<Fundamental, Tuple>::apply(t);
}

//
// some tag names to differentiate parameter 'name' types
//
struct a_tag { static constexpr int dflt = 0; };
struct b_tag { static constexpr int dflt = 1; };
struct c_tag { static constexpr int dflt = 2; };
//
// define some parameter 'names'
//
using a = fundamental<int, a_tag>;
using b = fundamental<int, b_tag>;
using c = fundamental<int, c_tag>;
//
// the canonical implementation of the function
//
void func(int a, int b, int c)
{
    std::cout << a << ", " << b << ", " << c << std::endl;
}
//
// a version that forwards the values of fundamental types in a tuple, or their default values if not present
//
template<class...Fundamentals>
void func(std::tuple<Fundamentals...> t)
{
    func(value_of<a>(t),
         value_of<b>(t),
         value_of<c>(t));
}
//
// a version that converts a variadic argument list of fundamentals into a tuple (that we can search)
//
template<class...Fundamentals>
void func(Fundamentals&&...fs)
{
    return func(std::make_tuple(fs...));
}
//
// a test
//
using namespace std;
auto main() -> int
{
    func();
    func(a(5));
    func(c(10), a(5));
    func(b(20), c(10), a(5));
    return 0;
}

预期输出:

0, 1, 2
5, 1, 2
5, 1, 10
5, 20, 10

您不能直接这样做,但可以使用命名参数习语(尽管受到批评)。

其想法是创建一个封装所有参数的对象,使用方法链接对其进行初始化,最后调用函数,因此代码看起来像:

int v = function(params(23).c(3));

使用命名参数习惯用法可以完成类似的操作。以下是使用可选参数(无默认参数值)时的情况:

/*
int function(int a, int b = 1, int c = 2){
  return a+b+c;
}
*/
int function( Parameters &p ) {
  /* ... */
}
void someOtherFunction() {
  function( Parameters().parmW(/*...*/)
                        /* parmX was omitted here */
                        .parmY(/*...*/)
                        .parmZ(/*...*/)
          );

添加默认参数可以通过几种方式完成。CCD_ 1可以替换为一个类,该类的目的是执行这些操作。Parameters也可以被写入以知道设置了哪些标志,然后function在开始执行之前传递默认值。我相信有很多方法可以做到这一点,也许有些比我建议的要好得多。