为什么静态常量char*模板结构成员未初始化 我有一些C++ 11模板代码,我试图把它移植到Visual C++编译器2015。最初的代码工作得很好,但是我需要重写它来解决constexpr的问题
为什么静态常量char*模板结构成员未初始化 我有一些C++ 11模板代码,我试图把它移植到Visual C++编译器2015。最初的代码工作得很好,但是我需要重写它来解决constexpr的问题,c++,templates,clang,constexpr,visual-c++-2015,C++,Templates,Clang,Constexpr,Visual C++ 2015,#include <iostream> struct String { static constexpr const char * value{ "STRING" }; }; template<typename Base> class Derived { public: static constexpr const char * value{ Base::value }; }; template<typename BarType> str
#include <iostream>
struct String
{
static constexpr const char * value{ "STRING" };
};
template<typename Base>
class Derived
{
public:
static constexpr const char * value{ Base::value };
};
template<typename BarType>
struct Foo
{
static constexpr const char * value{ BarType::value };
};
using Bar = Derived<String>;
using FooBar = Foo<Bar>;
int main()
{
std::cout << "FooBar::value = " << FooBar::value << std::endl;
}
#include <iostream>
struct String
{
static const char * value;
};
const char * String::value = "STRING";
template<typename Base>
class Derived
{
public:
static const char * value;
};
template<typename Base>
const char * Derived<Base>::value = { Base::value };
template<typename BarType>
struct Foo
{
static const char * value;
};
template<typename BarType>
const char * Foo<BarType>::value = { BarType::value };
using Bar = Derived<String>;
using FooBar = Foo<Bar>;
int main()
{
std::cout << "FooBar::value = " << FooBar::value << std::endl;
}
但是,当我重写时,一些静态变量没有初始化。即使它编译得很好
#include <iostream>
struct String
{
static constexpr const char * value{ "STRING" };
};
template<typename Base>
class Derived
{
public:
static constexpr const char * value{ Base::value };
};
template<typename BarType>
struct Foo
{
static constexpr const char * value{ BarType::value };
};
using Bar = Derived<String>;
using FooBar = Foo<Bar>;
int main()
{
std::cout << "FooBar::value = " << FooBar::value << std::endl;
}
#include <iostream>
struct String
{
static const char * value;
};
const char * String::value = "STRING";
template<typename Base>
class Derived
{
public:
static const char * value;
};
template<typename Base>
const char * Derived<Base>::value = { Base::value };
template<typename BarType>
struct Foo
{
static const char * value;
};
template<typename BarType>
const char * Foo<BarType>::value = { BarType::value };
using Bar = Derived<String>;
using FooBar = Foo<Bar>;
int main()
{
std::cout << "FooBar::value = " << FooBar::value << std::endl;
}
FooBar::value=STRING
更新:
正如@serge ballesta所建议的那样。我更喜欢这个解决方案,因为它与原始代码非常相似。当constexpr成员被添加到VS.时,很容易应用和删除。我认为问题来自[basic.start.init]: 如果变量是隐式或显式实例化的专用化,则具有静态存储持续时间的非局部变量的动态初始化是无序的
Derived::value
和Foo::value
的初始化不是静态初始化,因为右侧不是常量表达式。这使它成为动态初始化。由于变量是模板专门化的,因此初始化是无序的——也就是说,没有明确定义两个值的顺序
因此,我们有两种可能的顺序。有效的一个:
Derived<Base>::value ==> 0
Foo<BarType>::value ==> 0
Derived<Base>::value ==> Base::value
Foo<BarType>::value ==> BarType::value
Derived<Base>::value ==> 0
Foo<BarType>::value ==> 0
Foo<BarType>::value ==> BarType::value
Derived<Base>::value ==> Base::value
Derived::value==>0
Foo::value==>0
派生::值==>Base::值
Foo::value==>BarType::value
无效的一个:
Derived<Base>::value ==> 0
Foo<BarType>::value ==> 0
Derived<Base>::value ==> Base::value
Foo<BarType>::value ==> BarType::value
Derived<Base>::value ==> 0
Foo<BarType>::value ==> 0
Foo<BarType>::value ==> BarType::value
Derived<Base>::value ==> Base::value
Derived::value==>0
Foo::value==>0
Foo::value==>BarType::value
派生::值==>Base::值
如果首先初始化了Derived::value
,则Foo::value
将指向“STRING”
。否则,如果先初始化后者,它将被初始化为0
。您看到的分段错误是试图流式传输空字符指针的结果 @巴里给出了问题的原因
一种可能的解决方法是强制执行初始化命令。由于String
不是模板类,String::value
将在动态初始化之前正确初始化(静态)
我可以想象两种方式:
将显式init方法添加到Foo
中,而不是依赖于自动动态初始化:
...
template<typename BarType>
struct Foo
{
static const char * value;
static void init() {
Foo::value = BarType::value;
}
};
template<typename BarType>
const char * Foo<BarType>::value;
using Bar = Derived<String>;
using FooBar = Foo<Bar>;
int main()
{
FooBar::init();
std::cout << "FooBar::value = " << FooBar::value << std::endl;
}
为什么会发生什么?不是您所期望的吗?使用派生的模板类显式实例化这两个类;模板结构Foo代码>在使用@LightnessRacesinOrbit之前,我相信输出不是OP所期望的。@Mathias是的,我编辑掉了链接,因为代码应该在问题中。你应该知道,问题行为的真实描述。@Barry,同意!但链接也应该存在,以避免所有读者编译。谢谢!将@Barry的答案标记为正确,因为“为什么”是问题中最有趣的部分。您的第二个解决方案与原始代码非常相似。我认为这是最好的方法,当constexpr在VS中成熟时,恢复更改将很容易。我正在为这个问题添加一个解决方案示例。