2017-06-02 101 views
8

考虑下面的代码:推导引导和可变参数模板

#include <tuple> 
#include <iostream> 

template <class T> 
struct custom_wrapper 
{ 
    template <class Arg> 
    custom_wrapper(Arg arg): data(arg) {} 
    T data; 
}; 

template <class Arg> 
custom_wrapper(Arg arg) -> custom_wrapper<Arg>; 

template <class... T> 
struct custom_tuple 
{ 
    template <class... Args> 
    custom_tuple(Args... args): data(args...) {} 
    std::tuple<T...> data; 
}; 

template <class... Args> 
custom_tuple(Args... args) -> custom_tuple<Args...>; 

int main(int argc, char* argv[]) 
{ 
    custom_wrapper<int> w1(42); // OK 
    custom_wrapper w2(42);  // OK 
    custom_tuple<int> t1(42); // OK 
    custom_tuple t2(42);   // Fails 
    return 0; 
} 

失败下克++ 7返回以下错误的行:

variadic_deduction_guide.cpp: In instantiation of 'custom_tuple<T>::custom_tuple(Args ...) [with Args = {int}; T = {}]': 
variadic_deduction_guide.cpp:31:23: required from here 
variadic_deduction_guide.cpp:19:45: error: no matching function for call to 'std::tuple<>::tuple(int&)' 
    custom_tuple(Args... args): data(args...) {} 

是正常或是编译器故障?

回答

3

这是gcc bug 80871。接下来是解释为什么代码格式正确(并且在判定t2custom_tuple<int>时,clang是正确的)。


搞清楚做什么用

custom_tuple t2(42); 

主要涉及合成一组函数,并对其进行重载决策过程。有关的候选人是从一个构造函数合成的功能和演绎指南:

template <class... T, class... Args> 
custom_tuple<T...> foo(Args...);  // the constructor 

template <class... Args> 
custom_tuple<Args...> foo(Args...); // the deduction guide 

从这一点来说它是一个基于你什么是“尾随参数包”是根据[temp.arg.explicit]/3演绎一个选择自己的冒险:

未导出的尾随模板参数包将被推断为模板参数的空序列。如果可以推导出所有的模板参数,则可以全部省略;在这种情况下,空模板参数列表<>本身也可以被省略。

T...没有尾随

这种情况很容易。我们只有一个可行的候选人(因为T...不可扣除) - 扣除指南候选人。我们推断Args...{int},所以我们以custom_tuple<int>结束。

T...拖尾

GCC和铛其实也考虑扣除构造成功。所以,我们去的同分决赛中[over.match.best]

根据这些定义,一个可行的功能F1被定义为比另一种可行的功能F2如果更好函数[...]

  • F1F2是功能模板专业化,并且根据[temp.func.order]中描述的部分排序规则,F1的功能模板比F2的模板更专门化,或者,如果不是那样,
  • F1是从扣除指南([over.match.class.deduct])生成的,并且F2不是,或者如果不是,[...]

对于部分订货的目的,relevant types只是那些相应的功能参数,我们允许ignore unused template parameters,所以没有函数模板被认为比其他的更加专业化。

这让我们更喜欢扣除指南,这是整个过程中最简单的一步。我们推断Args...{int},所以我们以custom_tuple<int>结束。


无论哪种方式,custom_tuple<int>是正确的决定。

+0

嗯,海湾合作委员会和铿锵树干不同意OP的代码,我不是很确信这里。首先是'T'“尾随”? (这是一个相当不明确的术语。)其次,你能证明构造函数比扣除指南更专业吗? –

+0

@ T.C。但很酷,看到克朗与扣除指南工作!这一定是相当新的。 – Barry

+0

这里的上下文是一个函数调用,所以[“所使用的类型\ [对于偏序} \是那些函数调用具有参数的函数参数类型]](https://timsong-cpp.github.io/cppwp /temp.deduct.partial#3.1)。对于部分排序目的,[“一个模板参数可能保留没有值,只要它不用于用于部分排序的类型”](https://timsong-cpp.github.io/cppwp/temp.deduct。部分#12),而'T ...'不是。那么究竟如何比其他更专业?扣除失败的方向如何? –