请考虑以下类
定义和演绎指南:
template <typename... Ts>
struct foo : Ts...
{
template <typename... Us>
foo(Us&&... us) : Ts{us}... { }
};
template <typename... Us>
foo(Us&&... us) -> foo<Us...>;
如果我尝试使用显式模板参数实例化 foo
,代码将正确编译:
foo<bar> a{bar{}}; // ok
如果我试图通过演绎指南实例化< code>foo...
foo b{bar{}};
>
G7产生编译器错误:
prog.cc: In instantiation of 'foo<Ts>::foo(Us ...) [with Us = {bar}; Ts = {}]':
prog.cc:15:16: required from here
prog.cc:5:27: error: mismatched argument pack lengths while expanding 'Ts'
foo(Us... us) : Ts{us}... { }
^~~
clang 5 爆炸:
#0 0x0000000001944af4 PrintStackTraceSignalHandler(void*) (/opt/wandbox/clang-head/bin/clang-5.0+0x1944af4)
#1 0x0000000001944dc6 SignalHandler(int) (/opt/wandbox/clang-head/bin/clang-5.0+0x1944dc6)
#2 0x00007fafb639a390 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x11390)
#3 0x0000000003015b30 clang::Decl::setDeclContext(clang::DeclContext*) (/opt/wandbox/clang-head/bin/clang-5.0+0x3015b30)
...
clang-5.0: error: unable to execute command: Segmentation fault
wandbox上的实例
虽然clang肯定被窃听了(报告为问题#32673),但g拒绝我的代码是正确的吗?我的代码格式错误吗?
由于foo有一个构造函数,编译器会根据构造函数生成一个隐式演绎指南:
// implicitly generated from foo<T...>::foo<U...>(U...)
template<class... T, class... U> foo(U...) -> foo<T...>;
template<class... T> foo(T...) -> foo<T...>; // explicit
因此,问题在于gcc更喜欢隐式指南,因此将T
推导为{}
,将U
{bar}推导为;clang(根据godbolt从5.0.0开始)更喜欢显式指南。这是一个过载解决问题;当发现两个演绎指南不明确时,显式演绎指南优于隐式演绎指南。但clang和gcc在演绎指南是否模棱两可方面存在分歧:
template<class... T, class... U> int f(U...) { return 1; }
template<class... T> int f(T...) { return 2; }
int i = f(1, 2);
这个方案(完全不涉及推演指南)被gcc接受(选择#1),被clang拒绝(因为模棱两可)。追溯我们的步骤,这意味着回到演绎指南clang通过选择显式演绎指南而不是隐式演绎指南(从构造函数模板生成)来消除歧义,而gcc不能这样做,因为它已经选择了隐式演绎指南作为首选。
我们可以构建一个更简单的例子:
template<class... T, int = 0> int f(T...); // #1
template<class... T> int f(T...); // #2
int i = f(1, 2);
同样,gcc(不正确地)选择了#1,而clang以不明确为由拒绝。
重要的是,我们可以通过添加另一个显式推导指南来解决这个问题,gcc仍然更喜欢从构造函数生成的隐式推导指南:
template <typename U, typename... Us>
foo(U&& u, Us&&... us) -> foo<U, Us...>;
这是首选的(当提供的参数超过0时),因为它将第一个参数绑定到一个单一参数,而不是一个包。在0参数的情况下,选择哪个演绎指南(在原始显式指南和隐式生成的指南之间)并不重要,因为两者得到相同的结果,
foo
实例
为了进一步简化您的示例,GCC似乎没有在演绎指南中实现可变参数模板参数:
https://wandbox.org/permlink/4YsacnW9wYcoceDH
我没有在标准或 cppreference.com 的扣除指南的措辞中看到任何明确提及可变参数模板的内容。我没有看到对不允许这样做的标准的解释。因此,我认为这是一个错误。
假设有一个模板函数 接受任意数量的参数。给定最后一个参数始终是 ,我如何实现下面显示的 模板,以便 包含此 的参数? 例如,如果像这样调用,应该是: 我的第一个想法是: 但这不会编译: 问题一: 为什么这不能编译?为什么模板参数演绎失败? 最终,我想出了这个解决方案: 这里,是,即中的最后一种类型。然后,的临时值被传递到,其中。这行得通,但在我看来很难看。 问题二: 我想知道如果没有两个函数和的临
考虑以下代码: 失败的行在G7下返回以下错误: 这是正常的还是编译器错误?
在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty
以这种方式传递参数有问题,我得到以下错误:“std::thread::thread”:没有重载函数接受4个参数。我怎么能这么做?
以下是我的代码:< br > 一开始我只是重载了函数,发现有很多类似的代码。所以我正在考虑使用可变参数模板来获得更好的设计。(如果两个重载函数相似,如何做出更好的设计) 但是我不知道为什么会有错误:< br > main.cpp:27: 8:错误:没有匹配函数调用'getChar'ch=getChar(1, std::forward(str)...); 主要的cpp:37:2:注意:在函数模板专门
受这个答案的启发,我生成了这段代码,其输出取决于编译器: 如果使用 GCC 11 编译,调用