在 C++ 中使用默认参数跳过模板参数真的不可能吗,为啥语法建议不这样?

Posted

技术标签:

【中文标题】在 C++ 中使用默认参数跳过模板参数真的不可能吗,为啥语法建议不这样?【英文标题】:Is it really impossible to skip template parameters with default arguments in C++, why does syntax suggest otherwise?在 C++ 中使用默认参数跳过模板参数真的不可能吗,为什么语法建议不这样? 【发布时间】:2015-09-05 15:40:31 【问题描述】:

我一直在尝试找到一种方法来跳过不在模板参数列表末尾的模板参数,在派生类中,该派生类已在其基类中分配了默认值。

我已经对这个主题进行了一些研究,也在 SO 上进行了研究。虽然已经在 SO 上讨论了类似的问题 - 许多答案基本上表明它不起作用与非常特殊的情况有关,例如哈希映射案例 here。我还找到了“Potatoswatter”的this 答案,我认为这与跳过这样一个参数的可能性相矛盾。在他的回答中,他声称这个声明是有效的:

template< class A, class B = int, class C >
class X;

假设确实不能跳过模板参数(除非在参数列表的末尾),这样的声明根本没有意义。由于 B 被分配了一个默认值,但后面跟着没有默认值的 C,在这种情况下,总是必须显式地分配值 B,从而将 int 的分配作为 B 的默认值完全无用。上面 X 的声明有意义的唯一情况是以下 Y 的声明之一是有效的:

class Y : public X<double, , const std::string&>  ... 

class Y : public X<A = double, C = const std::string&>  ... 

那么在派生一个专门的类的时候,是不是真的不能跳过一个不在模板参数列表末尾的模板参数呢?

如果不可能,为什么会这样,为什么法律语法显然另有说明(参见上面的 X 类示例)?

如果事实上不是不可能,如何跳过已分配默认值的模板参数?

【问题讨论】:

我猜class A, class B = int, class C 是无效的,除非在同一个翻译单元中你确实有一个声明,其中C 一个默认值 好主意,还没有想到,这将是一个非常特殊的情况,声明会有意义,即使跳过无效。 【参考方案1】:

相关标准包含在“模板参数[temp.param]”(14.1)中。

本质上,只有在应用默认参数的参数后面没有任何没有默认参数的非包参数 ([temp.param]/11) 时,才可以使用默认参数。但是,您引用的语法可用于 [temp.param]/10 描述的情况下的声明:

可用的默认模板参数集是通过合并来自的默认参数获得的 模板的所有先前声明都以与默认函数参数相同的方式(8.3.6)。 [例子

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;

等价于

template<class T1 = int, class T2 = int> class A;

——结束示例]

【讨论】:

除了上面评论中提到的派生场景 Piotr 之外,你能想到任何例子吗? @norritt:不。不是你可以用 C++ 做的所有事情都是你应该做的。【参考方案2】:

“类”这个词有点隐藏在你的问题中,所以我想我会提到(即使这不是一个完全正确的答案)具有默认值的模板参数 可以 被“跳过” ",有点,在对 function 模板的调用中。考虑this code:

template<class X, class Y = int, class Z>
void foo(X x, Y y, Z z) 
    (void)x, (void)y, (void)z;
    puts(__PRETTY_FUNCTION__);


int main()

    foo(3.14, , 1.45f);

模板参数X 推导出为double(如果有默认值,将不使用)。 本次调用无法推导出模板参数Y,所以默认使用int。 模板参数Z推导出为float

由于 在函数参数列表中的不可推导性,如今在 STL 中经常为函数模板参数提供默认值。参见例如std::exchange 或constructor #8 of std::optional

您可能期望类似的技巧可以用于 C++17 中的构造函数模板参数推导,但我的实验表明情况并非如此。class 模板定义中,如果您将带默认的模板参数放在列表中的位置比不带默认的模板参数更早,编译器将生成诊断信息。

template<class X, class Y = int, class Z>  // error!
struct Foo ;

【讨论】:

以上是关于在 C++ 中使用默认参数跳过模板参数真的不可能吗,为啥语法建议不这样?的主要内容,如果未能解决你的问题,请参考以下文章

在 VC++2008 Express 中查找不依赖于模板参数的名称。它是一个错误吗?

使用模板参数模板解决模棱两可调用的 C++ 默认行为是啥?

在 C++ 模板中省略参数

C++中,为啥函数参数不够也可以调用?而且函数模板定义中没有提供默认值。

我可以从以前的参数中设置默认参数吗?

C++ - 从客户端代码中隐藏模板参数