在默认模板参数中调用constexpr

时间:2012-05-23 13:36:40

标签: c++ gcc c++11 clang constexpr

在C ++ 11中,我使用constexpr函数作为模板参数的默认值 - 它看起来像这样:

template <int value>
struct bar
{
    static constexpr int get()
    {
        return value;
    }
};

template <typename A, int value = A::get()>
struct foo
{
};

int main()
{
    typedef foo<bar<0>> type;

    return 0;
}

G ++ 4.5和4.7编译它,但Clang ++ 3.1没有。来自clang的错误消息是:

clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
                                  ^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
        typedef foo<bar<3>> type;
                ~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function 'get' cannot be used in a constant expression
template <typename A, int value = A::get()>
                                  ^
clang_test.cpp:4:23: note: declared here
        static constexpr int get()
                             ^
1 error generated.

哪一个是正确的?

2 个答案:

答案 0 :(得分:12)

LLVM IRC频道的Richard Smith(zygoloid)与我就这个问题进行了简短的谈话,这是你的答案

<litb> hello folks
<litb> zygoloid, what should happen in this case?
<litb> http://stackoverflow.com/questions/10721130/calling-constexpr-in-default-template-argument
<litb> it seems to be clang's behavior is surprising
<litb> zygoloid, i cannot apply the "point of instantiation" rule to constexpr 
  function templates. if i call such a function template, the called definition's 
  POI often is *after* the specialization reference, which means at the point of 
  the call, the constexpr function template specialization is "undefined".
<zygoloid> it's a horrible mess. Clang does not do what the standard intends, but 
  as you note, the actual spec is gloriously unclear
<d0k> :(
<zygoloid> we should instantiate bar<3>::get(), because it is odr-used, but we 
  don't, because we incorrectly believe it's used in an unevaluated context
<zygoloid> conversely, the point of instantiation is too late :/
<zygoloid> PR11851

所以似乎有时,Clang实例化称为函数模板或类模板的成员函数,但它们的实例化对于调用看起来太晚了,而在其他情况下它甚至不实例化它们因为它认为它永远不需要他们(未评估的背景)。

答案 1 :(得分:3)

我认为GCC Clang 是正确的

引自n3290:

  

14.3.2模板非类型参数[temp.arg.nontype]

     
      
  1. 非类型非模板模板参数的模板参数应为以下之一:    
         
    • 对于整数或枚举类型的非类型模板参数,转换后的&gt;模板参数类型的常量表达式(5.19);要么    
    • ...    
  2.   

编辑:5.19 3

  

文字常量表达式是prvalue核心常量表达式   文字类型,但不是指针类型。一个整数常量表达式   整数或无范围枚举的文字常量表达式   类型。 [注意:这样的表达式可以用作数组边界(8.3.4,   5.3.4),作为位字段长度(9.6),作为枚举器初始化器,如果基础类型不固定(7.2),则作为空指针常量(4.10),   作为路线(7.6.2)。 -end note]转换后的常量表达式   类型T是一个文字常量表达式,隐式转换为   类型T,其中允许隐式转换(如果有)   文字常量表达式和隐式转换序列   仅包含用户定义的转化,左值到右值的转化   (4.1),整体促销(4.5)和积分转换(4.7)其他   而不是缩小转换率(8.5.4)。

     

[注意:此类表达式可用作案例表达式(6.4.2),如果基础类型是固定的(7.2),则作为枚举器初始化器,以及作为整数或枚举非类型模板参数(14.3)。 - 后注]