clang - 如何在头文件中声明一个静态const int?

mar*_*964 3 static const clang one-definition-rule c++11

给定头文件中的以下模板,以及一些特殊化:

template<typename> class A {
        static const int value;
};

template<> const int A<int>::value = 1;
template<> const int A<long>::value = 2;
Run Code Online (Sandbox Code Playgroud)

并且使用clang-5进行构建时,会导致包含该文件的每个源单元出错,并且都会抱怨A<int>::value和的多个定义A<long>::value.

起初,我认为可能需要将模板特化放在特定的翻译单元中,但在检查规范时,显然应该允许这样,因为该值是一个常量整数.

我做错了什么吗?

编辑:如果我将定义移动到单个翻译单元,那么我就不能再使用A<T>::valuea的上下文中的const int值(例如,其值被用于计算另一个const赋值的值),所以该值确实需要在标题中.

Kla*_*aus 5

在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;
Run Code Online (Sandbox Code Playgroud)

如果您只想专门化值var,可以使用CRTP.

从C++ 17开始,您可以内联定义:

template<> inline const int A<int>::value = 1;
template<> inline const int A<long>::value = 2;
Run Code Online (Sandbox Code Playgroud)

同样从c ++ 17你可以删除'template const int B :: value;' 对于constexpr:

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;
Run Code Online (Sandbox Code Playgroud)

而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;
Run Code Online (Sandbox Code Playgroud)

除了上次编辑:

要在其他依赖定义中使用您的值,如果您使用内联constexpr方法,它似乎是最易读的版本.

编辑:clang的"特殊"版本,因为OP告诉我们,clang抱怨"实例化后发生的专业化".我不知道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;
}
Run Code Online (Sandbox Code Playgroud)

我已经说过CRTP是可能的,如果没有重新定义完整的类.我检查了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;
}
Run Code Online (Sandbox Code Playgroud)