【问题标题】:clang - how to declare a static const int in header file?clang - 如何在头文件中声明静态 const int?
【发布时间】:2017-11-02 06:56:02
【问题描述】:

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

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&lt;int&gt;::valueA&lt;long&gt;::value 的多个定义。

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

我做错了什么吗?

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

【问题讨论】:

  • 由于您定义专业化的变量,您仍然需要将它们放在一个翻译单元中。链接器将能够将它们放在一起。
  • 如果您需要使用常量的值来计算另一个常量的值(它需要知道分配时所有常量的值,如果我从标题中删除它可能不在同一个翻译单元中)。
  • 我不知道你为什么认为你必须在标题中初始化它。您可以在 .cpp 文件中定义 template&lt;&gt; const int A&lt;int&gt;::value = 1; template&lt;&gt; const int A&lt;long&gt;::value = A&lt;int&gt;::value + 1;。我错过了什么吗?
  • @cantordust 我认为 OP 的目标是使常量 compile-time 成为常量,因此它们可以在可以使用编译时常量的上下文中使用。
  • @Someprogrammerdude 我明白了。不过,这并不是很明显。

标签: c++11 static clang constants one-definition-rule


【解决方案1】:

在 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 cmets他不明白如何使用它:

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;
}

【讨论】:

  • @markt1964:我已经告诉过你可以使用 CRTP,但我现在还为你添加了一个示例。已经为 GetVar 方法添加了一个符合 clang 的版本。
猜你喜欢
  • 2010-12-10
  • 2016-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
  • 2017-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多