![](/img/trans.png)
[英]Can I use decltype() to avoid code duplication in explicit template instantiations?
[英]How can I concisely write a lot of explicit function template instantiations?
我正在編寫一個C ++庫,其中包含許多我希望顯式實例化並導出多個類型參數的函數模板。 在我的特定情況下,我有很多數字函數模板,我想單獨實例化和編譯float
, double
和long double
。 他們看起來像這樣:
template <typename T>
T calculate_a(T x) { ... }
template <typename T>
T calculate_b(T x, T y) { ... }
// ...
如果我有M個函數模板和N個底層類型,那么我有M * N顯式實例化來輸出。 是否可以更簡潔地編寫這些實例?
我目前的解決方案是使用預處理器宏來執行給定類型的所有實例化:
#define EXPLICITLY_INSTANTIATE(T) \
template T calculate_a<T>(T x); \
template T calculate_b<T>(T x, T y); \
// ...
EXPLICITLY_INSTANTIATE(float);
EXPLICITLY_INSTANTIATE(double);
EXPLICITLY_INSTANTIATE(long double);
但是,這不是最理想的,因為它要求我單獨維護每個函數模板簽名的另一個副本。 另外,如果我想在多個翻譯單元中執行此操作,那么我需要單獨維護每個翻譯單元中的基礎類型列表。 (假設C ++ 2a添加了一個我想支持的long long double
類型;我必須為每個文件添加EXPLICITLY_INSTANTIATE(long long double);
)
另一種可能的方法是將我的所有函數收集到(僅限靜態)模板類中:
template <typename T>
class calculate {
T a(T x) { ... }
T b(T x, T y) { ... }
};
template class calculate<float>;
template class calculate<double>;
template class calculate<long double>;
這解決了分別維護每個簽名的兩個副本的第一個問題,但是要求我將calculate_a
每個調用更改為calculate::a<T>
。 它沒有解決第二個問題。
這就是X Macros的用途。 它非常簡單。
您有一個文件,其中包含您要將其應用於的所有類型。 我們稱之為“type_list.inc”。 它看起來像這樣:
X(float)
X(double)
X(long double)
如果要對該類型列表執行某些操作,請#include
該文件,但在包含點附近,您#define
宏X
來執行您要執行的操作:
#define X(T) \
template T calculate_a<T>(T x); \
template T calculate_b<T>(T x, T y); \
// ...
#include "type_list.inc"
#undef X
您仍然需要維護兩組函數原型。 但是您只需要維護一個類型列表。
我沒有清楚地表達我對這個問題的意圖。 我的顯式實例化的目的不是限制可以調用這些函數的類型,而是通知編譯器為float,double和long double生成可執行代碼
好吧......如果所有類型都是默認的可構造的(如float
, double
和long double
)...在模板中使用折疊foo()
函數如下
template <typename ... Ts>
void foo ()
{ ((calculate_a(Ts{}), calculate_b(Ts{}, Ts{})), ...); }
並使用desidered類型調用foo()
foo<float, double, long double>();
我認為應該有用。
以下是完整的編譯示例
template <typename T>
T calculate_a (T x)
{ return x; }
template <typename T>
T calculate_b (T x, T y)
{ return x+y; }
template <typename ... Ts>
void foo ()
{ ((calculate_a(Ts{}), calculate_b(Ts{}, Ts{})), ...); }
int main ()
{
foo<float, double, long double>();
}
您可以通過獲取其地址來實例化模板,從而避免重復功能簽名:
// forward declarations in a header file
template<typename T>
T square(T num);
template<typename T>
T add(T left, T right);
// implementations and instantiations in a single implementation file
template<typename T>
T square(T num) {
return num * num;
}
template<typename T>
T add(T left, T right) {
return left + right;
}
// instantiations for specific types
#include <tuple>
template<typename... Ts>
auto instantiate() {
static auto funcs = std::tuple_cat(std::make_tuple(
add<Ts>,
square<Ts>
)...);
return &funcs;
}
template auto instantiate<int, double>();
這里的開銷是指向所有實例化函數的單個指針數組,例如godbolt 。
對所需類型使用常規重載並讓它們調用函數模板,如下所示:
float calculate_a(float x) { return calculate_a<float>(x); }
float calculate_b(float x, float y) { return calculate_b<float>(x, y); }
double calculate_a(double x) { return calculate_a<double>(x); }
double calculate_b(double x, double y) { return calculate_b<double>(x, y); }
long double calculate_a(long double x) { return calculate_a<long double>(x); }
long double calculate_b(long double x, long double y) { return calculate_b<long double>(x, y); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.