代码之家  ›  专栏  ›  技术社区  ›  markt1964

clang-如何在头文件中声明静态常量int?

  •  3
  • markt1964  · 技术社区  · 7 年前

    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

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

    我做错什么了吗?

    编辑:如果我将定义移动到单个翻译单元中,则我不能再使用 A<T>::value const int

    1 回复  |  直到 7 年前
        1
  •  5
  •   Klaus    7 年前

    在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中删除“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;
    

    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的“特殊”版本,因为正如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;
    }
    

    我已经说过,如果不重新定义完整的类,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;
    }