Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么静态常量char*模板结构成员未初始化 我有一些C++ 11模板代码,我试图把它移植到Visual C++编译器2015。最初的代码工作得很好,但是我需要重写它来解决constexpr的问题_C++_Templates_Clang_Constexpr_Visual C++ 2015 - Fatal编程技术网

为什么静态常量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;
}
  • 为什么会这样

  • 我如何修复/解决它

  • 这可以在Clang和Visual C++中重现,但在第二个示例中,GCC也会打印
    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中成熟时,恢复更改将很容易。我正在为这个问题添加一个解决方案示例。