std :: array <const T, n> против разрешения перегрузки std :: array <T, n> - PullRequest
0 голосов
/ 27 июня 2018

Проблема кажется достаточно простой, но я могу решить ее только "безобразным" способом. Вот короткий код:

#include <array>
struct A {
    A(int , int = 0) {}
    A(std::array<const int, 2>) {}
    //A(std::array<int, 2>) {}
};

int main(){
    std::array<int, 2> a = {0};
    const A x(a);
    return 0;
}

Как есть, компилятор пытается использовать конструктор A(int, int = 0) и, конечно, не может преобразовать std::array в int.

Комментирование первого конструктора дает явную ошибку компилятора, что std::array<int, 2> не может быть автоматически преобразован в его константный аналог. И это несколько озадачивает меня, так как я ожидаю, что преобразование неконстант в конст будет "тривиальным".

Проблема решена введением третьего конструктора (закомментированного в примере кода), но это выглядит как избыточное убийство.

Мои вопросы:

  1. Почему преобразование не-const в const здесь не выполняется автоматически?
  2. Можно ли это "исправить", не вводя третью неконстантную версию конструктора?
  3. Также помогает изменение конструктора, чтобы он принимал gsl::span вместо std::array, но также ощущается как избыточное убийство

Я компилирую в MSVC 2017 15.7.4 с использованием параметра C ++ 17.

1 Ответ

0 голосов
/ 27 июня 2018

1) Почему преобразование не-const в const здесь не выполняется автоматически?

Поскольку std::array<T, Dim> const и std::array<T const, Dim> - это разные типы и, как говорят мои clang ++, "нет известного преобразования из 'array<int, [...]>' в 'array<const int, [...]>'"

2) Можно ли это исправить, не вводя третью неконстантную версию конструктора?

А как насчет конструктора шаблонов

template <typename T>
A (std::array<T, 2> const &) {}

где T может совпадать с int и int const?

Если вы хотите навязать, что T - это всего лишь int или int const (а не, например, long const), вы можете сделать это через SFINAE с чем-то вроде

template <typename T>
A (std::array<T, 2>,
   std::enable_if_t<std::is_same<T const, int const>{}> * = nullptr)
 { }

Так что вы можете иметь

std::array<int, 2> a = {{0}};
std::array<int const, 2> b = {{0}};
std::array<long const, 2> c = {{0}};

const A x(a);  // compile
const A y(b);  // compile
const A z(c);  // compilation error

3) Также помогает изменение конструктора, чтобы он принимал gsl :: span вместо std :: array, но также выглядит как избыточное убийство

Извините, но я не понимаю третий вопрос (?) (И я не знаю gls::span)

...