2016-12-07 76 views
15

考虑粘贴在下面的代码。我已经定义了一个非常简单的类,为此编译器生成一个隐式演绎指南,因此它可以在没有显式模板参数的情况下构建。但是,模板参数推导工作从只直接转发到目标类的简单的别名模板构造一个对象:类别模板参数扣除不与别名模板一起使用

template< typename A, typename B > 
struct Foo { 
    Foo(A const &a, B const &b) 
      : a_(a), b_(b) 
    { } 

    A a_; 
    B b_; 
}; 

template< typename A, typename B > 
using Bar = Foo<A, B>; 

auto foobar() { 
    Foo r{1, 2}; 
    Bar s{3, 4}; 
    // ../src/geo/vector_test_unit.cpp: In function 'auto foobar()': 
    // ../src/geo/vector_test_unit.cpp:16:6: error: missing template arguments before 's' 
    // Bar s{3, 4}; 
    //  ^
    return 1; 
} 

正如你可以从上面的代码注释看,G ++是给我有关使用没有模板参数的别名模板的错误。我希望在这种情况下,模板论证扣除将被转发。

那么,我的问题:这是通过明确设计类模板参数演绎提案的当前措词吗?或者,这是该功能的当前g ++实现中未完成的功能或缺陷?这对于提案的作者或者C++ ISO委员会来说可能是一个更大的问题,但是如果他们中的任何一个人看到这样的话:这个特性的最后措辞是否包括启用别名模板也是理想的为他们生成隐式指南?

我可以理解,由于别名模板可以具有任何类型的模板参数,因此编译器可能无法总是成功推导出目标类模板参数,但在这种情况下,我希望编译器会是能够以同样的方式直接为目标课程。

我在前几天使用gcc构建gcc,使用--std=c++1z。完整版本信息是:gcc version 7.0.0 20161201 (experimental) (Homebrew gcc HEAD- --with-jit)

回答

21

这是我们在制定提案时考虑的一项功能,但最终因为我们还没有足够好的设计而被削减。特别是,关于如何选择和将别名模板中的演绎指南转换为别名模板的演绎指南,有一些细微之处。如果别名模板不是另一个模板的简单别名,那么对于如何表现还存在一些疑问。一些例子:

template<typename T> struct Q { Q(T); };  // #1 
template<typename T> struct Q<T*> { Q(T); }; // #2 
template<typename T> using QP = Q<T*>; 
int *x; 
Q p = x; // deduces Q<int*> using #1, ill-formed 
QP q = x; // deduces Q<int*> using #1, or 
      // deduces Q<int**> using #2? 

template<typename T> Q(T) -> Q<T>; // #3 
QP r = x; // can we use deduction guide #3 here? 

template<typename T> Q(T*) -> Q<T**>; // #4 
int **y; 
QP s = y; // can we use deduction guide #4 here? 

template<typename T> struct A { typedef T type; struct Y {}; }; 
template<typename T> using X = typename A<T>::type; 
template<typename T> using Y = typename A<T>::Y; 
X x = 4;   // can this deduce T == int? 
X y = A<int>::Y(); // can this deduce T == int? 

有像样的回答了上述问题,但解决这些问题增加了复杂性,似乎最好禁止用于C++ 17别名模板扣除,而不是急于东西瑕疵英寸

我预测我们将看到一篇来自费萨尔的文章,提出了C++ 20的这个特性。

+0

我一次建立并编译您的示例文件,试图逐步了解它。我只用#1,#2和行int * x编译了它; Q p = x;'。正如你所指出的,它会给出一个错误,除非我删除#2并重新编译。来自g ++的错误信息是'[...]错误:从'int *'到'int'的无效转换... Q p = x; ...注意:初始化'Q :: Q(T)[with T = int]'参数1'template struct Q {Q(T); };'。对我来说,就像你说的那样,它试图使用#2而不是#1。我不了解什么? –

+1

@squidbidness对于类模板参数推导,'Q p = x;'这一行使用#1推导'p'的类型为'Q '。选择该类型后,它推断'Q '应该使用'Q '部分专业化,推导出'T = int'。最后,它试图调用一个'Q '构造函数,其参数类型为'int *',因为唯一的构造函数(默认/复制/移动ctors除外)需要一个int类型,所以它不起作用。 –

+0

谢谢你的澄清。让我感到困惑的部分是我的心智模型已经推导出'p'的类型,并且选择一个模板专业化作为一个相同的过程。指出他们是单独的步骤帮助我更好地推理它。 –