作为可变模板参数的初始化列表

Initializer list as a variadic template argument

我有几个 类 A、B 和 F,它们都有不同的构造函数签名,例如:

class A {
public:
     A() {}
};

class B {
    double x_, y_;
public:
    B(double x, double y) : x_(x), y_(y) {}
};

class F {
    vector<unsigned> factors_;
public:
    F(std::initializer_list<unsigned> factors) : factors_(factors) {}
};

这些类的对象需要在某处注册,所以构造要经过一个工厂,像这样:

template<class R, typename... Args>
inline R & factory(Args &&... args)
{
    R * rp = new R(std::forward<Args>(args)...);
    /* do fancy stuff with rp... */
    return *rp;
}

这适用于 类 A 和 B,但不适用于 F,因为 typename... 想要采用一种或多种类型:

A & a = factory<A>();   // okay     
B & b = factory<B>(0.707107, 0.707107);  // okay
F & f = factory<F>({2, 3, 5, 7, 11});  // error: no matching function for call to ‘F::F()’ in factory

问题:有什么方法可以让它与一般的 factory<R>(args...) 语法一起工作吗?

我为 <F, std::initializer_list> 尝试了工厂函数的完全专业化,但要么搞砸了语法,要么在编译时没有被编译器作为工厂选择。

还有其他想法吗?

要回答这个问题:我看不到一种简单的方法来重用采用 initializer_list 的工厂方法。

我个人会在 class F 中添加一个构造函数,取 std::vector

F(const std::vector<unsigned>& factors) : factors_(factors) {}

并重写一个工厂方法:

template<class R>
inline R & factory(const std::vector<unsigned>& factors)
{
    R *rp = new R(factors);
    /* do fancy stuff with rp... */
    return *rp;
}

现在可以正常编译了。

Live code

如果您想避免代码重复,您应该考虑将 /* do fancy stuff with rp... */ 写在另一个函数中。

编辑

我不知道你想做什么,但你为什么不简单地使用这里:

F f2{2, 3, 5, 7, 11};

如果您只想用一些值填充 class F 向量,则不需要工厂。

这可能不是您喜欢的语法,但您可以强制工厂方法传递初始化列表:

F & f = factory<F>(std::initializer_list<unsigned>{2u, 3u, 5u, 7u, 11u});

我在这里明确地使文字无符号 - 虽然它们可以被 std::initializer_list<unsigned> 强制转换,但以下版本不是这种情况。

我能够在 factory():

的重载下工作
template<class R>
inline R& do_fancy_stuff_with(R *r)
{
    /* do fancy stuff here... */
    return *r;
}

template<class R, typename... Args>
inline R & factory(Args &&... args)
{
    R * rp = new R(std::forward<Args>(args)...);
    return do_fancy_stuff_with(rp);
}

template<class R, typename T>
inline R & factory(std::initializer_list<T> args)
{
    R * rp = new R(std::move(args));
    return do_fancy_stuff_with(rp);
}

A & a = factory<A>();
B & b = factory<B>(0.707107, 0.707107);
F & f = factory<F>({2u, 3u, 5u, 7u, 11u});

令我惊讶的是可变参数模板不能更好地与初始化列表一起使用。