作为可变模板参数的初始化列表
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;
}
现在可以正常编译了。
如果您想避免代码重复,您应该考虑将 /* 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});
令我惊讶的是可变参数模板不能更好地与初始化列表一起使用。
我有几个 类 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;
}
现在可以正常编译了。
如果您想避免代码重复,您应该考虑将 /* 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});
令我惊讶的是可变参数模板不能更好地与初始化列表一起使用。