clang,构造函数声明中首先需要隐式模板实例化

Dra*_*n D 1 c++ templates clang

这是我的问题的简单版本:

#include <iostream>

template<typename T>
class Extractor
{
public:
    static const int& value;
};

class Bar
{
    
};

template<typename T>
class Foo
{
public:
    Foo() {
        m_value = Extractor<Bar>::value;
    }
    
public:
    int m_value;
};

int gValue = 42;
template<> const int& Extractor<Bar>::value = gValue;

int main()
{
    Foo<Bar> test;
    std::cout << " Hello, world " << test.m_value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

g++ 没有给出错误并且显示正确。

clang 返回以下错误消息:

1184815205/source.cpp:30:39: error: explicit specialization of 'value' after instantiation
template<> const int& Extractor<Bar>::value = gValue;
                                      ^
1184815205/source.cpp:22:35: note: implicit instantiation first required here
        m_value = Extractor<Bar>::value;
Run Code Online (Sandbox Code Playgroud)

规范指定:

如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在发生这种使用的每个翻译单元中; 无需诊断。

在第一次使用该专业化之前, 我认为我的代码片段遵循此规则,导致模板的实际实例化出现在函数中main(), Foo 构造函数尚不应该被编译。我错过了什么吗?

提高模板专业化可以解决这个问题,但我负担不起。

Art*_*yer 5

由于Extractor<Bar>不依赖于T,因此可以实例化它以value在声明中查找或在实际实例化时进行查找。Clang 更加渴望,这是被允许的。

最简单的解决方法是简单地声明专门化Extractor<Bar>::value并稍后定义它:

class Bar
{
    
};

template<> const int& Extractor<Bar>::value;  // Declaration here

template<typename T>
class Foo
{
public:
    Foo() {
        m_value = Extractor<Bar>::value;  // Will use the specialzation
    }
    
public:
    int m_value;
};

int gValue = 42;
template<> const int& Extractor<Bar>::value = gValue;  // Actual definition
Run Code Online (Sandbox Code Playgroud)

或者伪造对模板参数的依赖:

template<typename T, typename... Dependencies>
struct dependent_type_identity { using type = T; };
template<typename T, typename... Dependencies>
using dependent_type_identity_t = typename dependent_type_identity<T, Dependencies...>::type;


m_value = Extractor<dependent_type_identity_t<Bar, T>>::value;
// Or
m_value = dependent_type_identity_t<Extractor<Bar>, T>::value;
Run Code Online (Sandbox Code Playgroud)