我有一个模板类是这样的:
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});
有没有一个好的方法来实现这一目标?
如果隐式转换是不可能的,可以加1只为Foo<1>
情况下,一个构造函数?
对于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
,因为这是在数组中指定。
您可以定义另一个重载的构造函数,然后使用委派,例如像这样:
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);
将工作。
稍微目前存在的方法是使用可变参数模板的构造函数。在其他解决方案的好处是,你的类不拥有一个构造函数,会导致编译错误(意外地呼吁Foo
尺寸小于1高单双层构造函数)。
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
时显式调用构造函数。
而另一个版本直接转发到您的存储变量。
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
事情是这样的:
#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);
}