簡體   English   中英

如何對參數化模板函數進行類型推導

[英]How can I do the type deduction on parameterized template function

#include <iostream>

template <typename... Ts> void Print(Ts... args) { 
  (std::cout << ... << args) << std::endl;
}

template <typename T> void Add(T a, T b) { Print(a + b); } 

template <typename T> void Sub(T a, T b) { Print(a - b); } 

template <typename T> void Mul(T a, T b) { Print(a * b); } 

template <typename F, typename... Fns> void CallFuncs(F a, F b, Fns... fns) { 
  (fns(a, b), ...);
};

void FunctionInvokeTest() { CallFuncs(1, 2, Add<int>, Mul<int>); }

int main() { 
  FunctionInvokeTest();
  return 0;
}

我想將模板函數作為參數傳遞,如上所示。 該代碼有效。 但是,我必須將<int>放在諸如Add<int>類的函數之后。

如果這是不可扣除的上下文,那么還有另一種方法可以讓我這樣寫,其中AddMul仍然是模板函數嗎?

CallFuncs(1,2, Add, Mul);

你不能直接做,但是你可以把函數變成函數對象:

struct Add {
    template<typename T>
    void operator()(T a, T b) {
        Print(a + b); } 
};

struct Mul {
    template<typename T>
    void operator()(T a, T b) {
        Print(a * b); } 
};

template<typename F, typename... Fns>
void CallFuncs(F a, F b, Fns... fns) {
    (fns(a, b), ...);
};

void FunctionInvokeTest() { 
    CallFuncs(1, 2, Add{}, Mul{});
}

T將從ab的類型推導出來。 在這個例子中,它將是int 要獲得double ,您需要double參數:

CallFuncs(1., 2., Add{}, Mul{});

或顯式類型規范:

CallFuncs<double>(1, 2, Add{}, Mul{});

這與標准庫(C++14 起)中的“菱形”函子非常相似。 例如,std::plus聲明是

template<class T = void>
struct plus;

如果Tvoid (例如,在std::plus<>{} ), plus::operator()推導出參數和返回類型。 典型的實現看起來像這樣(有一些小的簡化):

template<> struct plus<void> {
    template<typename Tp, typename Up>
    constexpr auto operator()(Tp&& t, Up&& u) const {
        return std::forward<Tp>(t) + std::forward<Up>(u);
    }
};

如果您可以將模板函數轉換為函子類,您可以這樣做:

struct Add {
    template <typename T>
    void operator ()(T a, T b) const { Print(a + b); } 
};

struct Sub
{
    template <typename T> void operator() (T a, T b) const  { Print(a - b); } 
};

struct Mul
{
    template <typename T> void operator() (T a, T b) const { Print(a * b); } 
};

然后你可以做

void FunctionInvokeTest() { CallFuncs(1, 2, Add{}, Mul{}); }

或者有更多類似的語法:

constexpr Add add{};
constexpr Mul mul{};

void FunctionInvokeTest() { CallFuncs(1, 2, add, mul); }

如果您無法更改您的函數,將它們包裝在 lambda 中可能會有所幫助:

void FunctionInvokeTest() { CallFuncs(1, 2,
                                      [](auto lhs, auto rhs) { Add(lhs, rhs); },
                                      [](auto lhs, auto rhs) { Mul(lhs, rhs); }); }

通過將函數參數移動到模板中的解決方法

template <typename F>
using BinaryOp = void(F, F); // function type

// fns is now a pack of function objects instead of types
template <typename F, BinaryOp<F>... fns>
void CallFuncs(F a, F b) { 
  (fns(a, b), ...);
};

void FunctionInvokeTest() {
    // the functions are now passed as template arguments alongside the desired numeric type
    CallFuncs<float, Add, Mul>(1, 2); 
}

https://godbolt.org/z/DutpHk

暫無
暫無

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

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