从initializer_list构造的麻烦

时间:2014-05-22 15:57:15

标签: c++ c++11 constructor initializer-list

我有一个类,它有许多不同的构造函数重载,其中一个来自initializer_list。不幸的是,当我在

中使用list-initialisation时会自动选择此项
class foo
{
  template<typename T>
  foo(T const&it);

  template<typename T>
  foo(std::initializer_list<T> list);
};

template<typename other>
foo bar(other const&it)
{
  return {it};
}

当第二个构造函数被调用时,而不是第一个构造函数。这是正确的,但反直觉,因此很危险。我怎么能防止这种情况?我很满意第二个构造函数专门针对list.size()==1的情况的解决方案。例如

template<typename T>
foo::foo(std::initializer_list<T> list)
  : foo(list.begin(), list.size()) {}

template<typename T>              // private constructor
foo::foo(const T*p, size_t n)
{
  if(n==1)
    foo::foo(p[0]);               // this does not what I want
  else {
    /* ... */
  }
}

我尝试从另一个构造函数中显式调用第一个构造函数。这可能吗? (代码编译,但似乎没有调用预期的构造函数或实际上任何构造函数)。我能做到这一点的唯一方法是使用贴牌新方法:

template<typename T>              // private constructor
foo::foo(const T*p, size_t n)
{
  if(n==1)
    ::new(this) foo(p[0]);        // seems to work
  else {
    /* ... */
  }
}

然而,如果不是完全危险的话,这至少是不优雅的。有更好的解决方案吗? 请注意,尝试复制第一个构造函数的工作而不是调用它并不是一个真正有用的解决方案,因为使用SFINAE的不同类型的参数会有许多不同的第一个构造函数。

1 个答案:

答案 0 :(得分:0)

也许您可以使用可变参数模板而不是initializer_list 类似的东西:

#include <type_traits>

// equivalent to std::is_same but for more type.
template <typename... Ts> struct are_same : std::false_type {};
template <typename T> struct are_same<T> : std::true_type {};
template <typename T, typename ...Ts> struct are_same<T, T, Ts...> : are_same<T, Ts...>  {};

class foo
{
    struct dummy_t {};
public:
    template <typename...Ts, typename = typename std::enable_if<(sizeof...(Ts) > 1) && are_same<typename std::decay<Ts>::type...>::value>::type>
    foo(Ts&&... args);

    template<typename T>
    foo(T const&it);

};