Делегирование конструктора с помощью std::array

#c #constructor #initializer-list #stdarray

Вопрос:

У меня есть класс, который получает a std::array в конструкторе. Ни за что на свете я не могу написать правильное и простое делегирование из std::initializer_list — только неловкой лямбды, которую я прокомментировал. Может ли кто-нибудь показать мне чистый и разумный способ без специального кода?

 #include <array>

class foo
{
  std::array<int,5> t_;
  
public:
  
  foo(): foo{{}}
  { }
  
  foo(std::initializer_list<int> il = {}): foo{ std::array<int,5>(il) }
      // foo { [il]() {
      //   std::array<int,5> tmp;
      //   std::size_t i = 0;
      //   for (auto ile: il)
      //     if (i >= tmp.size()) break;
      //     else tmp[i  ]=ile;
      //   return tmp;
      // }()}
  { }
                          
  foo(std::array<int,5> t): t_(t)
  { }
};
 

Это дает:

 g   -std=c  17 -pedantic -Wall -Wextra   -c -o t.o t.cpp
t.cpp: In constructor 'foo::foo(std::initializer_list<int>)':
t.cpp:12:69: error: no matching function for call to 'std::array<int, 5>::array(std::initializer_list<int>amp;)'
   12 |   foo(std::initializer_list<int> il = {}): foo{ std::array<int,5>(il) }
      |                                                                     ^
In file included from t.cpp:1:
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note: candidate: 'std::array<int, 5>::array()'
   94 |     struct array
      |            ^~~~~
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note:   candidate expects 0 arguments, 1 provided
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note: candidate: 'constexpr std::array<int, 5>::array(const std::array<int, 5>amp;)'
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note:   no known conversion for argument 1 from 'std::initializer_list<int>' to 'const std::array<int, 5>amp;'
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note: candidate: 'constexpr std::array<int, 5>::array(std::array<int, 5>amp;amp;)'
/usr/lib/gcc/x86_64-pc-cygwin/10/include/c  /array:94:12: note:   no known conversion for argument 1 from 'std::initializer_list<int>' to 'std::array<int, 5>amp;amp;'
t.cpp:12:71: error: no matching function for call to 'foo::foo(<brace-enclosed initializer list>)'
   12 |   foo(std::initializer_list<int> il = {}): foo{ std::array<int,5>(il) }
      |                                                                       ^
t.cpp:23:3: note: candidate: 'foo::foo(std::array<int, 5>)'
   23 |   foo(std::array<int,5> t): t_(t)
      |   ^~~
t.cpp:23:3: note:   conversion of argument 1 would be ill-formed:
t.cpp:12:3: note: candidate: 'foo::foo(std::initializer_list<int>)'
   12 |   foo(std::initializer_list<int> il = {}): foo{ std::array<int,5>(il) }
      |   ^~~
t.cpp:12:3: note:   conversion of argument 1 would be ill-formed:
t.cpp:9:3: note: candidate: 'foo::foo()'
    9 |   foo(): foo{{}}
      |   ^~~
t.cpp:9:3: note:   candidate expects 0 arguments, 1 provided
t.cpp:3:7: note: candidate: 'constexpr foo::foo(const fooamp;)'
    3 | class foo
      |       ^~~
t.cpp:3:7: note:   conversion of argument 1 would be ill-formed:
t.cpp:3:7: note: candidate: 'constexpr foo::foo(fooamp;amp;)'
t.cpp:3:7: note:   conversion of argument 1 would be ill-formed:
 

Комментарии:

1. вам действительно нужен std::initializer_list констуктор? Без этого вы уже можете создать foo через foo f{{1,2,3,4,5}};

Ответ №1:

std::array не имеет (никаких) явно объявленных конструкторов, и поэтому у него нет конструктора из списка инициализаторов, поэтому вы не можете просто перенаправить список инициализаторов в массив. В качестве обходного пути вы можете использовать конструктор шаблонов variadic

 template <typename ... Args>
foo(Args amp;amp; ... args) : foo(std::array<int, 5>({args ...}))
 

Комментарии:

1. Есть ли у RHS int a[] = { 1,2,3 }; какой-то тип, с которым это как-то связано std::initializer_list ?

2. @Vroomfondel, использующий агрегатную инициализацию. У него даже нет типа afaik.

3. @Vroomfondel нет, это старый синтаксис для инициализации c-подобных массивов и структур, который позже был расширен для всех других типов

Ответ №2:

Я думаю, что вы ищете этот синтаксис:

 Foo(const int(amp;values)[5]) 
 

Полный пример,

 #include <array>
#include <algorithm>
#include <iostream>

class Foo
{

public:
    Foo(const int(amp;values)[5])
    {
        std::copy(std::begin(values), std::end(values), std::begin(m_values));
    }

    const autoamp; values() const noexcept
    {
        return m_values;
    }

private:
    std::array<int, 5> m_values;
};

int main()
{
    Foo foo({ 1,2,3,4,5 });

    for (const autoamp; value : foo.values())
    {
        std::cout << value << " ";
    }

    return 0;
}