2016-12-31 32 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; 
}; 


的问题是,每次我都像这样

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


饲料0到模板参数传递给我的结构是否有任何解决方法来读取最后一个零?

注意:我是TMP的初学者。

+3

只是踢,这里有一个C + +14'constexpr'解决方案,不使用模板递归:http://melpon.org/wandbox/permlink/yNbfyOhiN3hLqmpA – bogdan

+0

很酷!!!有什么方法可以用其他解决方案进行基准测试吗? –

+0

你的意思是编译时间?非递归解决方案应该大致相同,并且优于涉及模板递归的经典解决方案,因为递归解决方案会产生多个模板实例化,这会产生一些成本(实际上,它开始对相对大量的模板参数起作用 - 许多数十个)。然而,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快照测试,但它没有通过。你是否有意从这里删除':: value' static -texd 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参数。 –

+0

@chedynajjar:它是一个部分专业化的完全专业化的替代品:其他方面都与您的方法一样。 –

+0

@DietmarKühl:我有一个编译时错误:'错误:错误的模板参数数量(0,应该至少为1) static constexpr std :: size_t value = n1 * mul_all :: value;' –

3

一种方法是专门为空的可变参数。对于你所需要的主模板只有可变参数ARGS:

// 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

你需要围绕fold表达式的parens,它们在语法中是强制性的。 – bogdan

相关问题