C++11,是否可以强制一个实例是外部的,但也是一个非类型模板参数的常量表达式?

C++11, Is it possible to force an instance to be extern but also a constant expression of a non-type template parameter?

使用 C++11、g++ (GCC) 4.4.7 20120313(Red Hat 4.4.7-18)。

假设我有一个模板函数(如果我的术语不太正确,请原谅我)。

我想根据本应是 "field" 的编译时实例执行 "general" 算法。唯一真正改变的是我移入 trait 类 中的这些常量(这里只添加了一个,但可以想象还有更多)。最初我将其声明为

constexpr field FIELD1{1};

但是在 C++11 中,非类型模板参数需要有外部链接(不像 C++14 可以有内部和外部链接?)。因此,因为不在同一个翻译单元中,所以我需要使用 extern 来为其提供外部链接(抱歉,如果我也扼杀了那个解释)。但是通过将它定义为 extern,我无法使用 constexpr 来定义它,而且似乎丢失了 constexpr 构造函数,这个字段不再是一个有效的常量表达式,无法作为非类型模板参数。

如果有什么办法可以解决这个问题,有什么建议吗?接受一种新的做事方法。下面是一个简化的(不完整的、非编译版本,以获取组织的要点)。

所以我看到的错误是

错误:“FIELD1”的值在常量表达式中不可用

注意:“FIELD1”未声明为“constexpr” 外部常量字段 FIELD1; 不太确定什么是最佳选择。

我可以通过从构造函数中删除 constexpr 来消除第二个错误。但是后来我不知道如何解决常量表达式问题。

field.H

struct field
{
    int thingone;

    constexpr field(int i):thingone(i){}
};

extern const field FIELD1;

field.C

#include "field.H"
const field FIELD1{0};

field_traits.H

#include "field.H"

template< const field& T >
class fieldTraits;

template< >
class fieldTraits<FIELD1>
{
    public:
        // Let's say I have common field names
        // with different constants that I want to plug
        // into the "function_name" algorithm
        static constexpr size_t field_val = 1; 
};

function.H

#include "field.H"

template< const field& T, typename TT = fieldTraits<T> >
void function_name()
{
    // Let's pretend I'm doing something useful with that data
    std::cout << T.thingone << std::endl;
    std::cout << TT::field_val << std::endl;
}

So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr [...]

根据我的评论,你可以。它对你不起作用,但它是一个有助于想出有用的东西的步骤:

extern constexpr int i = 10;

这是完全有效的,提供 i 外部链接,并使 i 可用于常量表达式。

但是它不允许多个定义,所以它不能在包含在多个翻译单元中的头文件中工作。

通常,解决方法是 inline:

extern inline constexpr int i = 10;

但在 C++11 中不能声明变量inline

除非...当它们不需要被声明时inline因为效果已经隐式实现了:

struct S {
  static constexpr int i = 10;
};

现在,S::i有外部链接并且可用于常量表达式!

您甚至可能不需要为此定义自己的 class,具体取决于常量的类型:考虑 std::integral_constant。你可以写

using i = std::integral_constant<int, 10>;

现在 i::value 将完全按照您的意愿进行。