我有一个像这样的模板类:
template<int dimension>
class Foo{
Foo(std::array<double, dimension>);
}
和一个函数
func(Foo<1> f);
我希望能够这样调用函数和构造函数:
func(1);
Foo<1> f(1);
代替
func({1});
Foo<1> f({1});
有没有很好的方法来实现这一目标?
如果无法进行隐式转换,则只能为Foo<1>
情况添加一个构造函数吗?
答案 0 :(得分:8)
无法将double
隐式转换为std::array<double, 1>
。这将需要重载double
的转换运算符,但这无法完成,因为您无法重载内置类型的运算符。
您可以做的就是添加
Foo(double);
构造函数,然后使用static_assert
之类的
static_assert(dimension == 1, "single double constructor only works if dimension == 1");
构造函数主体中的,以使其仅在数组大小为1
时才起作用。 (我喜欢使用static_assert
,因为它可以让您编写漂亮的,描述性的错误消息)
您应该考虑将dimension
重命名为size
,因为这是数组中指定的内容。
答案 1 :(得分:5)
您可以为构造函数定义另一个重载,然后使用委托,例如像这样:
template<int dimension>
class Foo{
public:
Foo(std::array<double, dimension>) {}
Foo(double init) : Foo(std::array<double, dimension>{{init}}) {}
};
这样,两个都需要调用
func(1);
Foo<1> f(1);
将起作用。
答案 2 :(得分:2)
一种稍微不同的方法是将可变参数模板用于构造函数。相对于其他解决方案,优点是您的类不拥有会导致编译错误的构造函数(通过意外地为尺寸大于1的Foo
调用单双精度构造函数)。
template <int dimension>
class Foo {
public:
Foo(std::array<double, dimension>) {}
template <typename... Is>
Foo(Is... inits) : Foo{std::array<double, sizeof...(Is)>{inits...}} {}
};
Foo<1> f1(1.);
Foo<2> f2(1., 2.);
缺点是使用std::array
时必须显式调用构造函数。
答案 3 :(得分:0)
还有另一个版本直接转发到您的存储变量。
template <int dimension>
class Foo {
public:
std::array<double, dimension> data;
template< class... Args >
Foo(Args&&... args) : data{std::forward<Args>(args)...} {}
};
Foo<1> one(1.);
Foo<2> two(1., 2.);
// Foo<2> three(1., 2., 3.); // error: too many initializers for
答案 4 :(得分:0)
类似这样的东西:
#include <array>
#include <iostream>
#include <type_traits>
template < int dimension >
struct Foo
{
Foo(std::array< double, dimension > x)
: store_(x)
{
std::cout << "array\n";
}
template < class... Args, std::enable_if_t< sizeof...(Args) == dimension > * = nullptr >
Foo(Args &&... args)
: store_ { { double(args)... } }
{
std::cout << "items\n";
}
std::array< double, dimension > store_;
};
template < class... Ts >
auto use(Ts &&...)
{
}
int main()
{
auto f1 = Foo< 1 >(std::array< double, 1 > { 1.0 });
auto f2 = Foo< 1 >(1.0);
use(f1);
use(f2);
auto f4 = Foo< 3 >(std::array< double, 3 > { 1.0, 2.0, 3 });
auto f3 = Foo< 3 >(1, 2, 3);
use(f3, f4);
}