Есть ли способ для неявного преобразования из двойного в std :: array? - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть такой шаблон класса:

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>только случай?

Ответы [ 5 ]

0 голосов
/ 07 февраля 2019

Примерно так:

#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);
}
0 голосов
/ 07 февраля 2019

И еще одна версия, напрямую пересылаемая в вашу переменную хранения.

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
0 голосов
/ 07 февраля 2019

Неявное преобразование для 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, поскольку это то, что указано вмассив.

0 голосов
/ 07 февраля 2019

Немного другой подход - использование вариадических шаблонов для конструктора.Преимущество перед другими решениями заключается в том, что у вашего класса нет собственного конструктора, который может привести к ошибкам компиляции (из-за случайного вызова конструктора типа single-double для 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.

0 голосов
/ 07 февраля 2019

Вы можете определить другую перегрузку для своего конструктора и затем использовать делегирование, например, так:

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

будут работать.

...