有没有办法从 double 隐式转换为 std::array<double,1>?

Is there a way for implicit conversion from double to std::array<double,1>?

我有一个这样的模板class:

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> 情况添加一个构造函数吗?

您可以为您的构造函数定义另一个重载,然后使用委托,例如像这样:

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);

会起作用。

无法将 double 隐式转换为 std::array<double, 1>。这将需要为 double 重载转换运算符,但这无法完成,因为您不能为内置类型重载运算符。

你可以做的是添加

Foo(double);

构造函数然后使用static_assert like

static_assert(dimension == 1, "single double constructor only works if dimension == 1");

在构造函数的主体中将其限制为仅在数组大小为 1 时才起作用。 (我喜欢尽可能使用 static_assert,因为它可以让你写出漂亮的、描述性的错误消息)


您应该考虑将 dimension 重命名为 size,因为这是数组中指定的内容。

一个略有不同的方法是为构造函数使用可变参数模板。与其他解决方案相比的优势在于,您的 class 没有可能导致编译错误的构造函数(通过不小心调用尺寸大于 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时必须显式调用构造函数。

还有另一个版本直接转发到您的存储变量。

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);
}