У меня была проблема в сильно шаблонном коде, и я изолировал ее в этом примере программы (я компилирую с 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)?
К первому вопросу о сообщении об ошибке:
Конструктор в OPTION==2
не считается конструктор списка инициализаторов, потому что такой конструктор должен иметь один std::initializer_list<E>
параметр (или такая ссылка) или все другие параметры должны иметь аргументы по умолчанию. (8.5.4 Инициализация списка [dcl.init.list] # 2).
Поэтому не найдя конструктор списка инициализаторов компилятор пробует другие конструкторы со списком аргументов, состоящим из элементов списка инициализатора, находит явный конструктор и, поскольку мы находимся в контексте неявного преобразования (инициализирующего параметр оператора присваивания), завершается с сообщением об ошибке.
Других решений пока нет …