2016-08-26 4 views
3

У меня был встроенный частично специализированный шаблонный код, работающий с VS 2015, пока я не обнаружил, что it was not standards-compliant. Я хочу, чтобы это было так, что я искал свой код для преодоления прежней проблемы, а также that one и теперь ударил по жесткой стене.Как заполнить массив содержимым пакета параметров шаблона?

Использование вариативных шаблонов и частичной специализации Я хотел бы заполнить массив во время компиляции с учетом фиксированного набора параметров.

То, что я хочу достичь, также похоже на this answer, но мне не удалось заставить его работать.

Рассмотрим следующую программу:

#include <cstdlib> 

template <typename T, std::size_t Size> 
struct Array; 

template <typename T, std::size_t Size, std::size_t Iteration, typename ...Args> 
struct ArrayFiller { 
    inline 
    static void fill(Array<T, Size>& a, const Args&... args) { 
     ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...); 
    } 

    inline 
    static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) { 
     a.data[Size - Iteration - 1] = i; 
     ArrayFiller<T, Size, Iteration - 1>::fill_recursive(a, args...); 
    } 
}; 

template <typename T, std::size_t Size> 
struct ArrayFiller<T, Size, 0> { 
    inline 
    static void fill_recursive(Array<T, Size>& a, const T& i) { 
     a.data[Size - 1] = i; 
    } 
}; 

template <typename T, std::size_t Size> 
struct Array { 
    T data[Size]; 

    template <typename ...Args> 
    Array(const Args&... args) { 
     ArrayFiller<T, Size, Size - 1, Args...>::fill(*this, args...); 
    } 
}; 

int main() { 
    Array<int, 2> c(42, -18); 
    return 0; 
} 

... и начало его g++ -std=c++14 -pedantic -Wall -Wextra вывода (в версии 5.3.0):

main.cpp: In instantiation of ‘static void ArrayFiller<T, Size, Iteration, Args>::fill(Array<T, Size>&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}]’: 
main.cpp:34:54: required from ‘Array<T, Size>::Array(const Args& ...) [with Args = {int, int}; T = int; long unsigned int Size = 2ul]’ 
main.cpp:39:28: required from here 
main.cpp:10:65: error: no matching function for call to ‘ArrayFiller<int, 2ul, 1ul, int, int>::fill_recursive(Array<int, 2ul>&, const int&, const int&)’ 
     ArrayFiller<T, Size, Iteration, Args...>::fill_recursive(a, args...); 
                   ^
main.cpp:14:17: note: candidate: static void ArrayFiller<T, Size, Iteration, Args>::fill_recursive(Array<T, Size>&, const T&, const Args& ...) [with T = int; long unsigned int Size = 2ul; long unsigned int Iteration = 1ul; Args = {int, int}] 
    static void fill_recursive(Array<T, Size>& a, const T& i, const Args&... args) { 
       ^
main.cpp:14:17: note: candidate expects 4 arguments, 3 provided 

В основном компилятор жалуется, что нет поскольку из того, что я понимаю, пакет параметров расширяется либо слишком «скоро», либо слишком «поздно» в моей логике: аргумент const T& i в рекурсивном вызове вызывает расширение.

Как вы его исправить?

Меня также интересуют альтернативные/лучшие/чистые решения.

+2

Зачем вам нужен вариационный шаблон, когда будет создан конструктор constexpr с инициализационным списком? – SergeyA

+0

Да, я не уверен, почему вы не просто используете 'std :: array', который поддерживает именно этот синтаксис ... Это не« заполнение »массива, что подразумевает генерирование значений; он просто инициализирует его из предоставленных значений. И когда стандартная библиотека C++ уже предоставила необходимое вам колесо, обычно это плохая идея, чтобы попытаться изобрести ее самостоятельно. –

+0

@SergeyA: не могли бы вы рассказать? Это то, о чем говорит Витторио? Извините, мне не так удобно с C++, как с другими инструментами. – dummydev

ответ

8

Является ли решение не основано на рекурсии шаблонов, приемлемой в вашем случае использования? wandbox link

template <typename T, std::size_t Size> 
struct Array { 
    T data[Size]; 

    template <typename ...Args> 
    constexpr Array(const Args&... args) : data{args...} { 

    } 
}; 

int main() { 
    Array<int, 2> c(42, -18); 
    assert(c.data[0] == 42); 
    assert(c.data[1] == -18); 

    constexpr Array<int, 2> cc(42, -18); 
    static_assert(cc.data[0] == 42); 
    static_assert(cc.data[1] == -18); 
} 
+0

Спасибо Витторио, это был глазник. Я добавил публичный сеттер, который просто выполняет '* this = Array (args ...);' для удовлетворения моих потребностей. – dummydev

Смежные вопросы