簡體   English   中英

將變量作為模板參數傳遞

[英]Passing a variable as a template argument

我正在使用一個庫,它公開了一個可以使用的接口。 這個庫的功能之一是這樣的:

template <int a>
void modify(){}

我必須將參數從 1 修改為 10,即使用模板 arguments 從 1 到 10 調用modify 。為此,我編寫了此代碼(代碼的基本版本,實際代碼要大得多)。

for(int i=0; i<10; i++){
    modify<i>();
}

在編譯時我收到以下錯誤

error: 'i' cannot appear in constant-expression

在瀏覽了互聯網上的一些鏈接之后,我開始知道我不能將任何值作為模板參數傳遞,而模板參數在編譯時不會被評估。 我的問題如下: 1.為什么編譯器不能在編譯時評估i 2. 在不改變 API 接口的情況下,還有其他方法可以實現我想要實現的目標嗎?


還有一件事我想做。 調用 modify as modify 其中 VAR 是一些函數計算的 output。 我怎樣才能做到這一點?

編譯時i的值(不是常數)是多少? 除非執行循環,否則無法回答。 但是執行不是“編譯”,因為沒有答案,編譯器不能那樣做。

模板不是要執行的算法,而是要擴展以生成代碼的宏。 您可以做的是依靠專業化通過遞歸實現迭代,如下所示:

#include <iostream>

template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }

template<int x, int to>
struct static_for
{
    void operator()() 
    {  modify<x>();  static_for<x+1,to>()(); }
};

template<int to>
struct static_for<to,to>
{
    void operator()() 
    {}
};


int main()
{
    static_for<0,10>()();
}

請注意,通過這樣做,您實際上是在實例static_for<0,10>::operator()modify<0> ... modify<9> 10 個函數,分別由static_for<0,10>::operator() ... static_for<9,10>::operator()

迭代結束,因為static_for<10,10>將從采用兩個相同值的特化實例化,什么都不做。

  1. “為什么編譯器不能在編譯時評估i ?”

    這將違背模板的目的。 模板用於某些情況下源代碼看起來相同的情況,但編譯器每次需要生成的指令都不同。

  2. “有沒有其他方法可以在不更改 API 接口的情況下實現我想要實現的目標?”

    是的,看看Boost.MPL

    但是我懷疑這里的正確答案是您想要更改 API。 這取決於modify函數的內部結構。 我知道你有它的來源,因為模板必須在標題中定義。 所以看看為什么它需要在編譯時知道i ,如果不需要,最好用帶參數的普通函數替換(或補充,如果你需要保持向后兼容性)它。

由於您使用Boost.MPL要求答案:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>

#include <iostream>

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

// You need to wrap your function template in a non-template functor
struct modify_t
{
    template <typename N>
    void operator()(N)
    {
        modify<N::value>();
    }
};

int main()
{
    namespace mpl = boost::mpl;

    mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}

不使用structBoost也可以做到:

#include <iostream>
#include <utility>

template <int a>
void modify()
{
    std::cout<<a<<",";
}

template<int i,size_t... t>
constexpr inline void CT_for_impl(std::integer_sequence<size_t,t...>)
{
    bool kai[]= { (modify<i+t>(), false)...};
}

template<int i,int n>
constexpr inline void CT_for()
{
    CT_for_impl<i>(std::make_index_sequence<n-i+1>());
}

int main()
{
    CT_for<-5,5>();
    return 0;
}

錯誤的解決方法:'i'不能出現在上述問題的常量表達式中

要了解 constexpr,請單擊此鏈接

#include <iostream>
using namespace std;

template <typename T>
void modify(T a)
{
    cout<<a<<endl;  //to check if its working 
}


//func converts int a into const int a
constexpr int func(int a)
{
    return a;
}

int main(){
    for(int i=0; i<10; i++){
        modify(func(i));//here passing func(i) returned value which can be used as template argument now as it is converted to constexpr    
}
    return 0;
}

鑒於您想在運行時通過索引調用函數並且您無法更改 API,您可以考慮類型擦除:

std::vector<std::function<void(int)> > func;
func.push_back(modify<1>);
func.push_back(modify<2>);
//... and so on ...
func.push_back(modify<10>);

for(int i=0; i<10; ++i)
{
    func[i]();  //calls modify<i+1>();
}

需要提及的幾點:

  • 這不是模板的主要用途,但它是將靜態庫帶入運行時世界的一種方式。 對此的基本要求是使用同構類型(--if modify<7>()將返回,例如,一個std::string整個方法會中斷)。
  • 以前使用類型擦除的解決方案有開銷。 可以通過使用函數指針更快地獲得它,但它仍然總是比在編譯時調用函數慢。
  • 還可以(並且應該)將push_back包裝到另一個迭代靜態函數中以避免手動調用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM