未定义的引用,模板结构和constexpr静态成员

时间:2015-10-26 03:20:48

标签: c++ templates c++14 static-members constexpr

我遇到了一个模板结构的静态constexpr成员的问题。代码编译但我得到链接错误。这就是我想要做的事情:

template<int n>
struct Test {
    static constexpr auto invoke = make_tuple(2, "test", 3.4);
};

template<typename T>
void test(T&& t) {
    cout << t << endl;
}

int main() {
    test(get<0>(Test<2>::invoke));
    return 0;
}

我发现链接错误,所以我尝试了这个:

template<int n>
struct Test {
    static constexpr auto invoke = make_tuple(2, "test", 3.4);
};

// declare it outside the class
template<int n>
constexpr decltype(Test<n>::invoke) Test<n>::invoke;

template<typename T>
void test(T&& t) {
    cout << t << endl;
}

int main() {
    test(get<0>(Test<2>::invoke));
    return 0;
}

但我得到了这个奇怪的错误:

error: redefinition of 'invoke' with a different type: 'const decltype(Test<n>::invoke)' vs 'const std::tuple<int, const char *, double>'

不同类型? 显然,非模板版本的工作正常:

struct Test {
    static constexpr auto invoke = make_tuple(2, "test", 3.4);
};

constexpr decltype(Test::invoke) Test::invoke;

template<typename T>
void test(T&& t) {
    cout << t << endl;
}

int main() {
    test(get<0>(Test::invoke));
    return 0;
}

如何让模板版本正常运行?非常感谢你

2 个答案:

答案 0 :(得分:3)

看起来你正在遇到一个有趣的角落案例,这个案例包含在decl bug报告 Static constexpr definitions used inside template中,其中包含以下示例,其中包含与您类似的错误:

  

这编译很好,但是当我创建A类时,这样的模板:

struct L
{
    void operator()() const
    {}
};

template<class X>
struct A
{
    static constexpr auto F = L();
};

template<class X>
constexpr decltype(A<X>::F) A<X>::F;

int main()
{
    A<void>::F();
    return 0;
}
     

Clang崩溃,如果我将F的定义行更改为:

template<class X>
constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F;
     

然后clang产生了这个错误:

error: redefinition of 'F' with a different type
constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F;
                                                                    ^
note: previous definition is here
    static constexpr auto F = L();
                          ^
理查德史密斯的回复如下:

  

此错误是正确的。 &#39; constexpr&#39;和&#39;汽车&#39;这里是红色的鲱鱼。   减少测试用例:

template<class X> struct A { static int F; };
template<class X> decltype(A<X>::F) A<X>::F;
     

Per C ++ 11 [temp.type] p2,&#34;如果表达式e涉及模板   参数,decltype(e)表示唯一的依赖类型。&#34;因此   A :: F的类型与模板中的类型不匹配。

C ++ 14草案的完整引用如下:

  

如果表达式e涉及模板参数,则decltype(e)表示   独特的依赖类型。两个这样的decltype-specifiers指的是   只有当它们的表达式相同时才是相同的类型(14.5.6.1)。 [ 注意:   但是,它可以是别名,例如,通过typedef-name。 - 后注]

我能看到的唯一明显的方法是:

template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;

错误报告中没有提供任何解决方法。

答案 1 :(得分:2)

  

如何让模板版本正常运行?

FWIW,您的方法在我的桌面上运行正常,它使用g ++ 4.8.4。

您可以使用:

disable: function(e) {
    $.ajax({
      context: this
      , type:"POST"
      , url:url 
      , success: function() {
          console.log(this);
        }
      , error: function() {
          console.log(this)
        }
    })
}

以下内容也适用于我的桌面:

template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;