2017-04-04 66 views
7

我想寫這樣的事情:迭代與constexpr

template<int i> void f() {} 

for (constexpr int i : {1,2,3}) 
{ 
    f<i>(); 
} 

是否有可能重複上constexpr?

謝謝

回答

5

正如你可能知道,你不能做類似的:

for (constexpr int i : {1,2,3}) 
{ 
    f<i>(); 
} 

因爲,如果i是從1到3的循環變化,那麼它是一個可變和 不是編譯時不變。並且變量不能是模板參數, 與f<i>中一樣:只有編譯時常量可以是模板參數。

在C++ 11以後,由於variadic templates, 可以有效迭代編譯時的arbitary序列通過使用接受的模板參數的合適的任意序列 模板函數的編譯時遞歸常數 。

這將幾乎意味着什麼給你,如果你已經不知道該怎麼做。 這裏是一個C++ 11例如,你想要表達什麼:

#include <type_traits> 
#include <iostream> 

template<int i> void f() 
{ 
    std::cout << i << '\n'; 
} 

// This overload is chosen when there is only 1 template argument. 
template<int First, int ...Rest> 
typename std::enable_if<sizeof...(Rest) == 0>::type 
for_each_f() 
{ 
    f<First>(); 
} 

// This overload is chosen when there is > 1 template argument. 
template<int First, int ...Rest> 
typename std::enable_if<sizeof...(Rest) != 0>::type 
for_each_f() 
{ 
    f<First>(); 
    for_each_f<Rest...>(); 
} 

int main() 
{ 
    for_each_f<2,3,5,7,11>(); 
    return 0; 
} 

See it live

另外可變參數模板,這種技術依賴於非常重要的C++元編程的SFINAE 原則,在std::enable_if, 這是標準C++庫提供的利用SFINAE的工具。

101010的答案演示了C++ 14中提供的更復雜,更強大的 解決方案(如果您編寫一些輔助樣板文件,可以輕鬆實現C++ 11 )。

+0

TBH我更喜歡這種方法。 'int t []'(C++的錯誤,而不是101010's)的初始化過程中有很多可怕的駭人聽聞的事情,在我選擇沿着這條路線前,我將不得不給予大量的錢! –

+0

如果您將模板簽名更改爲template,則可以將'enable_if's除去for_each_f();'和template for_each_f();'template ' –

5

不,您不能在編譯時使用for循環進行迭代。 C++中的for控制結構用於運行時控制流。

但是,您可以使用其他編譯時設施。例如在C++ 14中,您可以通過以下方式實現您想要的功能:

  1. 定義將調用您的函數的模板包裝類。

    template<int i> 
    struct wrapper { 
        void operator()() const { f<i>(); } 
    }; 
    
  2. 使用std::index_sequence生成編譯時間指數。

    template<template<int> class W, std::size_t... I> 
    void caller_impl(std::index_sequence<I...>) { 
        int t[] = { 0, ((void)W<I>()(), 1)... }; 
        (void) t; 
    } 
    
    template<template<int> class W, std::size_t N, typename Indices = std::make_index_sequence<N>> 
    void call_times() { 
        caller_impl<W>(Indices()); 
    } 
    
  3. 然後調用作爲

    int main() { 
        call_times<wrapper, 42>(); 
    } 
    

    Live Demo

如果C++ 14是不是一種選擇,你可以看看here你如何實現你的自我std::index_sequence

+0

什麼是'(void)t'? –

+1

@DeanSeo抑制未使用變量的編譯器警告。 – 101010

+0

如果你有C++ 17,那麼'caller_impl'函數體可以是'(W ()(),...);'更容易理解。 –