clang - 如何在 header 文件中声明一个 static const int?
clang - how to declare a static const int in header file?
给定 header 文件中的以下模板,以及一些专业化:
template<typename> class A {
static const int value;
};
template<> const int A<int>::value = 1;
template<> const int A<long>::value = 2;
并使用 clang-5 构建,它会导致包含该文件的每个源单元出错,所有这些都抱怨 A<int>::value
和 A<long>::value
.
的多个定义
起初,我认为模板特化可能需要放在特定的翻译单元中,但在检查规范时,这显然应该被允许,因为该值是一个常量整数。
我是不是做错了什么?
编辑:如果我将定义移动到单个翻译单元中,那么我就不能再在 const int
的上下文中使用 A<T>::value
的值(例如,它的值在哪里用于计算另一个 const 赋值的值),因此该值确实需要在 header.
在 c++11 中你也许可以这样做:
template<typename> class B {
public:
static const int value = 1;
};
template<> class B<long> {
public:
static const int value = 2;
};
template<typename T> const int B<T>::value;
如果您只想特化值 var,可以使用 CRTP。
从 C++17 开始,您可以使定义内联:
template<> inline const int A<int>::value = 1;
template<> inline const int A<long>::value = 2;
你也可以从 c++17 中删除 constexpr 的 'template const int B::value;':
template<typename> class C {
public:
static constexpr int value = 1;
};
template<> class C<long> {
public:
static constexpr int value = 2;
};
// no need anymore for: template<typename T> const int C<T>::value;
c++11 的另一个解决方案是使用内联方法而不是 c++17 允许的内联变量:
template<typename T> class D {
public:
static constexpr int GetVal() { return 0; }
static const int value = GetVal();
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template< typename T>
const int D<T>::value;
除了您上次编辑:
要在其他依赖定义中也使用您的值,如果您使用内联 constexpr 方法,它似乎是最易读的版本。
编辑:clang 的 "Special" 版本,因为正如 OP 告诉我们的那样,clang 抱怨 "specialization happening after instantiation"。不知道是clang还是gcc那个地方写错了...
template<typename T> class D {
public:
static constexpr int GetVal();
static const int value;
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template <typename T> const int D<T>::value = D<T>::GetVal();
int main()
{
std::cout << D<int>::value << std::endl;
std::cout << D<long>::value << std::endl;
}
我已经说过 CRTP 是可能的,如果不是的话,应该重新定义完整的 class。我检查了 clang 上的代码,它编译时没有任何警告或错误,因为 OP 评论说他不明白如何使用它:
template<typename> class E_Impl {
public:
static const int value = 1;
};
template<> class E_Impl<long> {
public:
static const int value = 2;
};
template<typename T> const int E_Impl<T>::value;
template < typename T>
class E : public E_Impl<T>
{
// rest of class definition goes here and must not specialized
// and the values can be used here!
public:
void Check()
{
std::cout << this->value << std::endl;
}
};
int main()
{
E<long>().Check();
std::cout << E<long>::value << std::endl;
E<int>().Check();
std::cout << E<int>::value << std::endl;
}
给定 header 文件中的以下模板,以及一些专业化:
template<typename> class A {
static const int value;
};
template<> const int A<int>::value = 1;
template<> const int A<long>::value = 2;
并使用 clang-5 构建,它会导致包含该文件的每个源单元出错,所有这些都抱怨 A<int>::value
和 A<long>::value
.
起初,我认为模板特化可能需要放在特定的翻译单元中,但在检查规范时,这显然应该被允许,因为该值是一个常量整数。
我是不是做错了什么?
编辑:如果我将定义移动到单个翻译单元中,那么我就不能再在 const int
的上下文中使用 A<T>::value
的值(例如,它的值在哪里用于计算另一个 const 赋值的值),因此该值确实需要在 header.
在 c++11 中你也许可以这样做:
template<typename> class B {
public:
static const int value = 1;
};
template<> class B<long> {
public:
static const int value = 2;
};
template<typename T> const int B<T>::value;
如果您只想特化值 var,可以使用 CRTP。
从 C++17 开始,您可以使定义内联:
template<> inline const int A<int>::value = 1;
template<> inline const int A<long>::value = 2;
你也可以从 c++17 中删除 constexpr 的 'template const int B::value;':
template<typename> class C {
public:
static constexpr int value = 1;
};
template<> class C<long> {
public:
static constexpr int value = 2;
};
// no need anymore for: template<typename T> const int C<T>::value;
c++11 的另一个解决方案是使用内联方法而不是 c++17 允许的内联变量:
template<typename T> class D {
public:
static constexpr int GetVal() { return 0; }
static const int value = GetVal();
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template< typename T>
const int D<T>::value;
除了您上次编辑:
要在其他依赖定义中也使用您的值,如果您使用内联 constexpr 方法,它似乎是最易读的版本。
编辑:clang 的 "Special" 版本,因为正如 OP 告诉我们的那样,clang 抱怨 "specialization happening after instantiation"。不知道是clang还是gcc那个地方写错了...
template<typename T> class D {
public:
static constexpr int GetVal();
static const int value;
};
template <> inline constexpr int D<int>::GetVal() { return 1; }
template <> inline constexpr int D<long>::GetVal() { return 2; }
template <typename T> const int D<T>::value = D<T>::GetVal();
int main()
{
std::cout << D<int>::value << std::endl;
std::cout << D<long>::value << std::endl;
}
我已经说过 CRTP 是可能的,如果不是的话,应该重新定义完整的 class。我检查了 clang 上的代码,它编译时没有任何警告或错误,因为 OP 评论说他不明白如何使用它:
template<typename> class E_Impl {
public:
static const int value = 1;
};
template<> class E_Impl<long> {
public:
static const int value = 2;
};
template<typename T> const int E_Impl<T>::value;
template < typename T>
class E : public E_Impl<T>
{
// rest of class definition goes here and must not specialized
// and the values can be used here!
public:
void Check()
{
std::cout << this->value << std::endl;
}
};
int main()
{
E<long>().Check();
std::cout << E<long>::value << std::endl;
E<int>().Check();
std::cout << E<int>::value << std::endl;
}