无法在不定义模板变量的情况下声明模板变量

时间:2016-01-24 00:17:55

标签: c++ templates c++14 variable-templates

我想在头文件中转发声明变量模板,然后在单独的编译单元中实际实例化。

我被认为C ++ 14变量模板的运行方式与静态类变量非常相似。不幸的是,这似乎并非如此,它阻止我向前声明我的变量模板。

template <typename T> struct Variable {
    static int variable;
};

template <typename T> 
extern int variable;

int main() {
    (void) Variable<char>::variable;
    // (void) variable<char>;                   // <-- line 10
}

template <> int Variable<char>::variable = 42;
template <> int variable<char> = 23;

上面的代码示例在GCC下编译并按原样运行。但是,取消注释第10行会产生编译时错误:

specialization of 'variable<char>' after instantiation
    template <> int variable<char> = 23;
                     ^

2 个答案:

答案 0 :(得分:1)

我认为你走在正确的轨道上。

诀窍是:在任何一个翻译单元中,不要在专业化之前实例化模板。

例如:

// test.h
#ifndef TEST_H
#define TEST_H

template <typename T> 
extern int variable;

template <> extern int variable<char>;
template <> extern int variable<int>;

#endif // TEST_H

然后:

// test2.cpp
#include "test.h"

template <> int variable<char> = 23;
template <> int variable<int> = 24;

最后:

// test.cpp
#include "test.h"
#include <iostream>

int
main()
{
    std::cout << variable<char> << '\n';
    std::cout << variable<int> << '\n';
}

对我来说这是输出:

23
24

<强>更新

T.C。在下面的评论中指出专业化需要在首次使用之前声明,所以我已经更新了上面的“test.h”来做到这一点。

更新2

似乎存在一些实施差异。 clang似乎处理了这个罚款:

template <typename T> 
extern int variable;

template <> extern int variable<char>;
template <> extern int variable<int>;

#include <iostream>

int
main()
{
    std::cout << variable<char> << '\n';
    std::cout << variable<int> << '\n';
}

template <> int variable<char> = 23;
template <> int variable<int> = 24;

http://melpon.org/wandbox/permlink/DGYKvvoPbmRIHaFi

然而gcc给出错误:

prog.cc:4:13: error: explicit template specialization cannot have a storage class
 template <> extern int variable<char>;
             ^~~~~~

prog.cc:5:13: error: explicit template specialization cannot have a storage class
 template <> extern int variable<int>;
             ^~~~~~

我搜索了标准和核心问题列表,我找不到任何指示一个编译器或另一个是正确的。如果有人确实看到了这样的证据,我很乐意将其包含在这个答案中。

答案 1 :(得分:0)

我也遇到了同样的问题,经过一番研究找到了解决方案。

TL;DR:实例化,而不是专门化模板。使用 extern template int variable<int>,而不是 template extern int variable<int>

似乎 extern template 是 C++ 中的一个特性,它使模板函数成为外部符号,而不是每次都编译。通常这是加快编译时间的一个技巧,但在我们的例子中它很适合。

所以整个解决方案是:

变量.h

// Declare a template variable.
template <typename T> 
extern int variable;

// Implicit instantiation of variable declaration.
extern template int variable<int>;

变量.cpp

// Define a template variable.
template <typename T>
int variable = 42;

// Implicit instantiation of variable definition.
template int variable<int>;

我没有尝试过其他编译器,但它适用于 clang 10。

我为 extern template 找到了一些 reference