2016-12-31 5 views
6

Мне нужно вычислить произведение кучки чисел во время компиляции, отправленное в шаблонную структуру. Мне удалось сделать некрасиво решение:template Metaprogramming: умножая кучу аргументов шаблона

template<std::size_t n1, std::size_t ...args> 
struct mul_all 
{ 
    static constexpr std::size_t value = n1 * mul_all<args...>; 
}; 
template<> 
struct mul_all<0> 
{ 
    static constexpr std::size_t value = 1; 
}; 


Проблема заключается в том, что каждый раз, когда я должен кормить 0 до шаблонных аргументов моей структуры, как так

int main() 
{ 
    std::cout << mul_all<1,2,5,4,5,7,0>::value << " " 
       << mul_all<4,2,0>::value; 
    return 0; 
} 


есть ли какое-либо обходное решение, чтобы прочитать этот последний ноль?

примечание: я новичок в TMP.

+3

Просто для Пинки, вот C + +14 'constexpr' решение, которое не использует рекурсию шаблона: http://melpon.org/wandbox/permlink/yNbfyOhiN3hLqmpA – bogdan

+0

cool !!! есть ли способ сравнить его с другим решением? –

+0

Вы имеете в виду время компиляции? Рекуррентные решения должны быть примерно одинаковыми и лучше, чем классические с рекурсией шаблонов, поскольку рекурсивные производят несколько экземпляров шаблонов, которые стоят что-то (на практике это начинает иметь значение при относительно большом числе аргументов шаблона - многие десятки из них). Однако решение Dummy массива C++ 14 является всего лишь обходным решением для отсутствия складчатых выражений; Я бы выбрал C++ 17-кратные выражения всякий раз, когда они доступны. – bogdan

ответ

6

В C++ 17, с откидным выражение, вы можете непосредственно сделать

template<std::size_t ...args> 
struct mul_all 
{ 
    static constexpr std::size_t value = (args * ...); 
}; 

Перед тем, вы должны сделать частичную специализацию:

template<std::size_t n1, std::size_t ...args> 
struct mul_all 
{ 
    static constexpr std::size_t value = n1 * mul_all<args...>::value; 
}; 

template<std::size_t n> 
struct mul_all<n> 
{ 
    static constexpr std::size_t value = n; 
}; 
+0

Ваше предложение классно, но оно не компилировалось, к сожалению, я скопировал и прошёл код, протестированный с моментальным снимком GCC 7.0.0, но он не прошел. вы удалили «:: значение» намеренно из здесь 'static constexpr std :: size_t value = n1 * mul_all ;' –

+0

@chedynajjar: Действительно, ':: value' отсутствовал во втором фрагменте, исправлен. – Jarod42

5

Вы должны заменить специализацию с:

template<std::size_t n1, std::size_t ...args> 
struct mul_all 
{ 
    static constexpr std::size_t value = n1 * mul_all<args...>::value; 
}; 

template<std::size_t n> 
struct mul_all<n> 
{ 
    static constexpr std::size_t value = n; 
}; 
+0

у вас нет рекурсии в вашем решении, и я даже не вижу varidic args. –

+0

@chedynajjar: это замена вашей полной специализации частичной специализацией: все остальное остается таким же, как в вашем подходе. –

+0

@ DietmarKühl: Я получил ошибку времени компиляции: 'ошибка: неправильное количество аргументов шаблона (0, должно быть не менее 1) static constexpr std :: size_t value = n1 * mul_all :: значение;' –

3

Одним из способов является специализироваться для пустых списков параметров. Для этого вам необходимо основной шаблон, чтобы быть только VARIADIC арг:

// main template never used 
template<std::size_t ...args> struct mul_all 
{ 
}; 

// specialization for at least one arg 
template<std::size_t n1, std::size_t ...args> 
struct mul_all<n1, args...> 
{ 
    static constexpr std::size_t value = n1 * mul_all<args...>::value; 
}; 

// specialization for empty args 
template<> 
struct mul_all<> 
{ 
    static constexpr std::size_t value = 1; 
}; 

Итак, теперь вы можете сделать:

+0

Это правильный способ сделать рекурсию шаблона. Нет необходимости передавать количество аргументов шаблона в качестве параметра шаблона. –

2

C++ 17 подход делают, что просто и красиво:

template <std::size_t... A> 
constexpr std::size_t mul = (A * ... * std::size_t(1u)); 

int main() { 
    constexpr std::size_t val = mul<1, 2, 3, 4>; 
} 

Для существующих версий C++ вы должны частично специализировать случай mul<v>:

template <std::size_t... V> struct mul; 
template <std::size_t V> struct mul { 
    statuc constexpr std::size_t value = V; 
}; 
template <std::size_t V, std::size_t... T> struct mul { 
    statuc constexpr std::size_t value = V * mul<T...>::value; 
}; 
template <std::size_t... V> 
using mul_v = mul<V...>::value; 

int main() { 
    constexpr std::size_t v = mul_v<1, 2, 3, 4>; 
} 
+1

Я предполагаю, что версия C++ 17 больше похожа на '(A * ... * 1U)'. – bogdan

+0

@bogdan: да, действительно - в настоящее время я не могу легко скомпилировать, но надеюсь, что теперь это исправлено. Благодаря! –

+0

Вам нужны парсеры вокруг выражения сложения, они обязательны в грамматике. – bogdan

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