Проблемы со связью при использовании статического constexpr в качестве аргумента конструктора по умолчанию - PullRequest
0 голосов
/ 27 марта 2019

Я бы хотел, чтобы кто-нибудь разъяснил, в каких случаях безопасно использовать 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 Ответ

2 голосов
/ 27 марта 2019

Как указывает 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...