模板类中静态常量成员的初始化

7

我有一个关于“static const”成员初始化的问题。在一个模板类中,我定义了一个const成员,并在类外初始化它。
当我在多个.cpp文件中包含实现该类的.h文件时,我会遇到LNK2005错误(我使用VS2010),该错误表示常量已经被定义

// List.hpp
template <class T>
class List {
    static const double TRIM_THRESHOLD;
};

template <class T>
const double List<T>::TRIM_THRESHOLD = 0.8;

我尝试将成员初始化放在.cpp文件中,但是然后我遇到了链接器错误,说常量根本没有定义。如果列表不是模板化的,并且我将初始化放在.cpp文件中,一切都很好。
有什么解决这种情况的办法吗?我已经在文件周围添加了#ifdef/define条款,但这绝对不是一个解决方案。


1
在定义中缺少“const”修饰符。 - Ropez
1
你确定这是你的代码吗?你不应该会出现任何错误。@Ropez:const 关键字只在声明时有用。 - GManNickG
有趣的是,VS2015没有这个问题。它可以优化/找出静态常量定义实际上都是相同的东西,并且不会在链接器中标记错误。 - Menace
可能是重复问题,参考如何定义模板类的静态常量变量 - 463035818_is_not_a_number
1个回答

9

您应该在源文件中定义常量而不是头文件中(这样它只会被定义一次),因为这是一个模板,您需要将其保留在头文件中(并且所有实例的值都相同),您可以使用一个共同的基类。

class ListBase {
protected:
    ListBase() {} // use only as base 
    ~ListBase() { } // prevent deletion from outside
    static const double TRIM_THRESHOLD;    
};

template <class T>
class List : ListBase {  
};

// in source file
double ListBase::TRIM_THRESHOLD = 0.8;

另一个选项是将其作为静态函数:
(注:该句为HTML标签,请保留)
    static double trim_threashold() { return 0.8; }

编辑:如果您的编译器支持C++11,您可以将static方法作为constexpr函数,这样它就具有直接使用该值的所有优化机会。


我认为你的观点是错误的。请看https://dev59.com/BXI_5IYBdhLWcg3wDOdC - cybevnm
1
我认为他没有错,因为他使用了继承,其中静态成员位于祖先类中,而不是模板类中。因此,使用静态函数也是有效的。 - uray
如果我们需要在模板的每个实例化中使用相同的常量值(例如TRIM_THRESHOLD在List<int>或List<float>中是相同的),那么Motti的解决方案是正确的。但是,如果我们只是为了避免链接器错误(多个相同符号的定义),那么这个解决方案有些过度了。语言允许我们在头文件中定义模板类的静态变量。如果Motti指的是第一种情况,那我很抱歉,因为我没有理解他的观点。 - cybevnm
1
为了完整起见,当静态成员是模板的成员时,您应该展示如何定义静态成员。 - 463035818_is_not_a_number

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接