初始化列表和转换为一切,构造顺序

initializer list and conversion to everything, construction order

情况如:

#include <utility>
#include <typeinfo>
#include <iostream>

struct C1
{
    char const* str; 
    template <typename T> operator T() const { std::cout << "Convert to " << typeid(T).name() << "\n"; return {}; }
};

struct C2
{
    C2(C1 const&) { std::cout << "C2(C1)\n"; }
    C2(std::initializer_list<std::pair<char const*, int>>) { std::cout << "C2(list)\n"; }
};

int main()
{
    C1 c1{};
    C2 c2{c1};
}

输出表明正在调用 C2(list)

我想为 C1 参数调用 C2(C1),但我需要 std::initializer 列表的参数保持可推导和可转换,我不能用可变参数替换它- 模板版本。我只是想控制构建顺序,但是这里//2甚至不是模板。假设 type std::pair 可以在正常情况下反序列化。可以使用 C++14

您可以使用 explicit 关键字来防止构造函数进行隐式类型转换:

    explicit C2(std::initializer_list<std::pair<char const*, int>>) {} // 2

参见:What does the explicit keyword mean in C++?

以下 selects C2(C1) 两种样式的样式,{...}({...})(在严格的 C++11 标准中,对于 ({...})样式,它将 select 第二个,因为 C1 是一个聚合和适用于它的特殊规则。对于更新的标准,情况不再如此。)。这通过使第二个构造函数不再是初始化构造函数来实现。

template<typename T>
struct id { typedef T type; };

struct C1 {
    char const* str; 
    template <typename T> operator T() const 
    { std::cout << "Convert to " << typeid(T).name() << "\n"; return {}; }
};

struct C2 {
    C2(C1);
    template<typename T = std::initializer_list<std::pair<char const*, int>>>
    C2(typename id<T>::type);
};

int main() {
    C1 c1{};
    C2 c2{c1};
    C2 c21({c1});
}