使用静态constexpr作为默认构造函数参数时的链接问题

时间:2019-03-27 08:37:36

标签: c++ c++11

我希望有人澄清在哪种情况下使用static constexpr作为类的构造函数的默认参数是安全的。要确切清除正在发生的情况,请考虑以下代码:

#include <array>
#include <iostream>

struct Bar {

    using Option = size_t;
    using Options = std::array<Option, 0>;
    static constexpr Option default_option = 8080;
    static constexpr Options default_options{};

    //template <typename OptionT = Options>
    Bar(
        Options options = default_options,
        Option  option  = default_option  
       ){
        std::cout << "Constructed with option " << option << std::endl;
    }
};

int main() {
    Bar bar;
}

该代码似乎可以编译,但无法链接。具体来说,在使用GCC 6.3进行编译时,我得到

prog.cc:(.text+0x13): undefined reference to `Bar::default_options'
collect2: error: ld returned 1 exit status

但是,如果我们注释掉违规行,那么代码将正确编译,链接并运行。因此,假设使用static constexpr size_t作为默认参数没有问题:

#include <array>
#include <iostream>

struct Bar {

    using Option = size_t;
    using Options = std::array<Option, 0>;
    static constexpr Option default_option = 8080;
    static constexpr Options default_options{};

    //template <typename OptionT = Options>
    Bar(
        //Options options = default_options,
        Option  option  = default_option  
       ){
        std::cout << "Constructed with option " << option << std::endl;
    }
};

int main() {
    Bar bar;
}

有人可以向我解释为什么链接对size_t有效,而对array无效吗?

我知道我可以这样定义内联的默认选项:

Bar(
    Options options = std::array<Option, 0>{},
    Option  option  = default_option  
   ){
    std::cout << "Constructed with option " << option << std::endl;
}

我只是想知道是否还有其他更好的修复程序,以便任何人都可以轻松查询默认选项。

1 个答案:

答案 0 :(得分:2)

正如StoryTeller指出的那样,第一个代码确实可以编译并与C ++ 17和GCC 7.1+链接。为了使其能够与C ++ 11和旧版GCC一起编译,您需要数组的类外声明:

#include <array>
#include <iostream>

struct Bar {

    using Option = size_t;
    using Options = std::array<Option, 0>;
    static constexpr Option default_option = 8080;
    static constexpr Options default_options{};

    //template <typename OptionT = Options>
    Bar(
        Options options = default_options,
        Option  option  = default_option  
       ){
        std::cout << "Constructed with option " << option << std::endl;
        std::cout << "Constructed with options..." << std::endl;
        for (auto & other_option : options)
            std::cout << other_option << ", ";
        std::cout << std::endl;
    }
};

// !!!! Needed for C++11 and lower gcc<7.1 versions
constexpr Bar::Options Bar::default_options;

int main() {
    Bar bar;
}