c++ - 初始化列表、可变参数模板和构造函数推导 : a strange case

标签 c++ constructor c++11 variadic-templates initializer-list

我在高度模板化的代码中遇到了问题,我在这个示例程序中将其隔离(我使用 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++的bug?

此外,我需要一个解决方法:我必须实现没有选项 1 的选项 2 构造函数。对我来说最明显的事情是使用启用 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)。

因此,如果找不到初始化列表构造函数,编译器会尝试使用由初始化列表的元素组成的参数列表的其他构造函数,找到显式构造函数,并且,因为我们处于隐式转换(初始化赋值运算符的参数)失败并显示错误消息。

关于c++ - 初始化列表、可变参数模板和构造函数推导 : a strange case,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13763578/

相关文章:

c++ - boost 日期时间转换和添加秒数

Java深度克隆问题

c# - 如何防止 C# 中的继承者调用基本构造函数?

c++ - 隐式默认可构造的含义?

c++11 to_string 与 code::blocks -std=c++11 flag already selected

c++ - 为什么用于打印输入数字分隔符的简单程序停止工作?

c++ - 在 STL 中将列表元素移动到末尾

c++ - 通过引用或指针传递 vector

multithreading - 使用类成员函数时std::thread构造函数按引用传递

c++ - 从成员函数指针转换为另一种类型并返回,严格别名问题?