未定义的引用、模板结构和 constexpr 静态成员
Undefined reference, template struct and constexpr static member
我在使用模板结构的静态 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;
}
如何使模板版本生效?非常感谢
How can I get the template version to work?
FWIW,你的方法在我的桌面上运行良好,它使用 g++ 4.8.4。
您可以使用:
template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;
以下也适用于我的桌面:
template<int n>
struct Test {
static constexpr auto invoke = make_tuple(2, "test", 3.4);
typedef decltype(invoke) invoke_t;
};
template<int n>
constexpr typename Test<n>::invoke_t Test<n>::invoke;
看起来你 运行 陷入了一个有趣的 decltype 极端案例,这在 clang 错误报告 Static constexpr definitions used inside template 中有所介绍,其中有以下示例,其中的错误与你的类似:
This compiles fine, but when I make the class A, a template like this:
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 crashes, if I change the definition line for F to this:
template<class X>
constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F;
Then clang produces this error:
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();
^
理查德·史密斯的回复如下:
This error is correct. 'constexpr' and 'auto' are red herrings here.
Reduced testcase:
template<class X> struct A { static int F; };
template<class X> decltype(A<X>::F) A<X>::F;
Per C++11 [temp.type]p2, "If an expression e involves a template
parameter, decltype(e) denotes a unique dependent type." Therefore the
type of A::F does not match the type in the template.
C++14 草案的完整引用如下:
If an expression e involves a template parameter, decltype(e) denotes
a unique dependent type. Two such decltype-specifiers refer to the
same type only if their expressions are equivalent (14.5.6.1). [ Note:
however, it may be aliased, e.g., by a typedef-name. —end note ]
我认为完成这项工作的唯一明显方法是:
template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;
错误报告中未提供解决方法。
我在使用模板结构的静态 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;
}
如何使模板版本生效?非常感谢
How can I get the template version to work?
FWIW,你的方法在我的桌面上运行良好,它使用 g++ 4.8.4。
您可以使用:
template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;
以下也适用于我的桌面:
template<int n>
struct Test {
static constexpr auto invoke = make_tuple(2, "test", 3.4);
typedef decltype(invoke) invoke_t;
};
template<int n>
constexpr typename Test<n>::invoke_t Test<n>::invoke;
看起来你 运行 陷入了一个有趣的 decltype 极端案例,这在 clang 错误报告 Static constexpr definitions used inside template 中有所介绍,其中有以下示例,其中的错误与你的类似:
This compiles fine, but when I make the class A, a template like this:
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 crashes, if I change the definition line for F to this:
template<class X> constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F;
Then clang produces this error:
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(); ^
理查德·史密斯的回复如下:
This error is correct. 'constexpr' and 'auto' are red herrings here. Reduced testcase:
template<class X> struct A { static int F; }; template<class X> decltype(A<X>::F) A<X>::F;
Per C++11 [temp.type]p2, "If an expression e involves a template parameter, decltype(e) denotes a unique dependent type." Therefore the type of A::F does not match the type in the template.
C++14 草案的完整引用如下:
If an expression e involves a template parameter, decltype(e) denotes a unique dependent type. Two such decltype-specifiers refer to the same type only if their expressions are equivalent (14.5.6.1). [ Note: however, it may be aliased, e.g., by a typedef-name. —end note ]
我认为完成这项工作的唯一明显方法是:
template<int n>
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke;
错误报告中未提供解决方法。