2016-12-31 33 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

相關問題