Список инициализаторов, вариационные шаблоны и вывод конструктора: странный случай

У меня была проблема в сильно шаблонном коде, и я изолировал ее в этом примере программы (я компилирую с g ++ 4.7.1):

#include <iostream>
#include <initializer_list>
#include <type_traits>
#define OPTION 2

// Test class
template<typename T = double>
class MyClass
{
public:
// Constructors
MyClass(const MyClass<T>& source)
{std::cout<<"copy constructor"<<std::endl;}

#if OPTION == 1
template<typename T2 = T>
MyClass(const std::initializer_list<T2>& source)
{std::cout<<"init constructor"<<std::endl;} // OPTION 1
#elif OPTION == 2
template<typename T2 = T, class... Misc>
MyClass(const std::initializer_list<T2>& source, const Misc&... misc)
{std::cout<<"init+misc constructor"<<std::endl;} // OPTION 2
#endif

template<class... Misc>
explicit MyClass(const Misc&... misc)
{std::cout<<"misc constructor"<<std::endl;}

// Assignment
inline MyClass<T>& operator=(const MyClass<T>& rhs)
{std::cout<<"copy assignment"<<std::endl; return *this;}

template<class Misc>
inline MyClass<T>& operator=(const Misc& rhs)
{std::cout<<"misc assignment"<<std::endl; return *this;}
};

// Main
int main(int argc, char* argv[])
{
MyClass<double> x;
x = {4., 8., 15., 16., 23., 42.}; // CALL LINE
return 0;
}

Проблема в следующем. С OPTION == 1, все в порядке, и CALL LINE вызывает «конструктор инициализации».

Но с OPTION == 2, У меня есть следующее сообщение об ошибке:

error: converting to ‘const MyClass<double>’ from initializer list would use
explicit constructor ‘MyClass<T>::MyClass(const Misc& ...) [with Misc = {double,
double, double, double, double, double}; T = double]’

Вопрос в том, почему? Это нормально или это ошибка в g ++?

Более того, мне нужен обходной путь: я должен реализовать конструктор варианта 2 без варианта 1. Самым очевидным для меня было бы заблокировать вызов явного конструктора с включенной функцией if, например:

    template<class... Misc, class std::enable_if<SOMETHING>::type>
explicit MyClass(const Misc&... misc)
{std::cout<<"misc constructor"<<std::endl;}

Моя проблема: что я могу написать вместо SOMETHING для того, чтобы заблокировать каждый std::initializer_list<T2> (для всех типов T2)?

2

Решение

К первому вопросу о сообщении об ошибке:

Конструктор в OPTION==2 не считается конструктор списка инициализаторов, потому что такой конструктор должен иметь один std::initializer_list<E> параметр (или такая ссылка) или все другие параметры должны иметь аргументы по умолчанию. (8.5.4 Инициализация списка [dcl.init.list] # 2).

Поэтому не найдя конструктор списка инициализаторов компилятор пробует другие конструкторы со списком аргументов, состоящим из элементов списка инициализатора, находит явный конструктор и, поскольку мы находимся в контексте неявного преобразования (инициализирующего параметр оператора присваивания), завершается с сообщением об ошибке.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]