在默认的模板参数调用constexpr(Calling constexpr in default t

2019-06-24 17:43发布

在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编译这一点,但锵++ 3.1没有。 从铛的错误信息是:

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.

哪一个是正确的?

Answer 1:

理查德·史密斯(zygoloid)在LLVM IRC频道曾与我有关此问题的简短谈话这是你的答案

<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

如此看来,有时候,锵实例调用的函数模板或类模板的成员函数,但他们的实例是来不及呼叫看到,而在其他情况下,因为它认为它永远不会需要他们,它甚至不实例化它们(未评估上下文)。



Answer 2:

我认为GCC 是正确的

从n3290报价:

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

  1. 模板参数的用于非类型的,非模板的模板参数应是以下之一:
    • 用于整型或枚举类型,模板参数的类型的一个转换>常量表达式(5.19)的非类型模板参数; 要么
    • ...

编辑:5.19 3

字面上的常量表达式是文本类型的prvalue核心常量表达式,但是没有指针类型。 整数表达式中是一体的或无作用域枚举类型的字面常量表达式。 [注意:这样的表达可以用作数组边界(8.3.4,5.3.4),作为位字段的长度(9.6),作为初始值设定枚举如果底层类型是不固定的(7.2),作为空指针常数(4.10 ),并且作为比对(7.6.2)。 末端说明】A转换的类型T的常量表达式是一个常量表达式,隐式转换为类型T,其中,所述隐式转换(如果有的话)被允许在一个文本常量表达式和隐式转换序列仅包含用户定义的转换,左值到右值转换(4.1),积分优惠(4.5),和积分的转化率(4.7)比缩小转换(8.5.4)其他。

[注意:这样的表达式可以被用作壳体的表达式(6.4.2),作为初始值设定枚举如果底层类型是固定的(7.2),和作为整体的或枚举非类型模板参数(14.3)。 末端注]



文章来源: Calling constexpr in default template argument