2009-08-15 5 views
6

Скажем, я хочу Си ++ для выполнения арифметических операций над двумя входами, рассматривая их в качестве данного типа:Передать указатель-в-шаблон-функцию в качестве аргумента функции?

псевдо:

function(var X,var Y,function OP) 
{ 
if(something) 
    return OP<int>(X,Y); 
else if(something else) 
    return OP<double>(X,Y); 
else 
    return OP<string>(X,Y); 
} 

функции, которые соответствуют ОП могут быть как:

template <class T> add(var X,var Y) 
{ 
return (T)X + (T)Y; //X, Y are of a type with overloaded operators 
} 

Итак, вопрос в том, как будет выглядеть подпись для функции? Если функции оператора не являются шаблонами, я могу это сделать, но я запутался в этой дополнительной сложности.

+1

Посмотрите на аргументы шаблона шаблона. (И это не опечатка.) – sbi

+0

+1, это в основном правильный ответ, как пройти OP. – MSalters

+0

Я добавил это как ответ. Надеюсь, я не допустил никаких глупых ошибок. – sbi

ответ

4

Вы ищете это?

template<class T> T add(T X, T Y) 
{ 
    return X + Y; 
} 

Или вы ищете что-то, что называет что-то вроде добавления?

template<class T, class F> 
T Apply(T x, T y, F f) 
{ 
    return f(x, y); 
} 

Вызывается через:

int x = Apply(2, 4, add<int>); 
+0

Я считаю, что он хочет передать * добавить * ** без ** указания * int * в качестве аргумента шаблона. – izogfif

5

Я немного запутался ... почему тип дифференциации в вашем псевдо-коде?

шаблоны C++ позволяют полный тип вычет на шаблонах:

template <typename T, typename F> 
T function(T x, T y, F op) { 
    return op(x, y); 
} 

Здесь F подходит что-нибудь (особенно функции), которые могут вызываться с синтаксисом вызова в () функции и принимать ровно два аргумента типа T (или неявно конвертируемый в него).

+0

Я думаю, что это то, что я имел в виду, не думал о функции как аргументе шаблона. –

+0

Единственная проблема заключается в том, что F не может быть функцией шаблона с неизвестными аргументами шаблона, либо должна быть функция без шаблона, либо функция шаблона со всеми указанными его типами шаблонов. – izogfif

+0

@izogfif Вы также можете явно указать аргументы шаблона. Выведение их может быть выполнено с помощью метапрограммирования шаблонов. Но, как бы то ни было, кажется, что это ответило на вопрос ФП, не нужно его усложнять. –

0

Я не уверен, что это var вещь в вашем вопросе означает. Это, конечно, не допустимое ключевое слово C++, поэтому я предполагаю, что это тип, похожий на boost:any. Кроме того, в функции отсутствует тип результата. Я добавил еще var, что бы это ни было. Ваше решение может выглядеть следующим образом:

template< template<typename> class Func > 
var function(var X, var Y, Func OP) 
{ 
if(something) 
    return OP<int>(X,Y); 
else if(something else) 
    return OP<double>(X,Y); 
else 
    return OP<string>(X,Y); 
} 

смешной аргумент шаблона является сам шаблон, отсюда и его название «шаблон аргумент шаблона». Вы передаете имя шаблона, а не экземпляр. То есть, вы передаете std::plus, а не std::plus<int>:

return function(a, b, std::plus); 
+0

Не работает в Visual C++ 2008, Visual C++ 2010 из-за ошибки компиляции. – izogfif

+0

@izogfif: Теперь, на мгновение, вы указали точную ошибку компилятора. Кто-то, возможно, пришел, посмотрел на него, понял, в чем проблема, и разместил решение. Конечно, мы этого не хотим, так что хорошо, что вы этого не сделали. – sbi

+0

Хорошая точка. Вот код, который я пытался скомпилировать, и ошибки, возникшие у компилятора (в конце кода): http://pastebin.com/YyhX9ruT – izogfif

5

функция шаблон не может быть передана в качестве аргументов шаблона. Вы должны вручную вывести аргументы шаблона для этой функции, прежде чем передавать ее в другую функцию шаблона.Например, у вас есть функция

T sum(T a, T b) 
{ 
    return a + b; 
} 

Вы хотите передать его callFunc:

template<typename F, typename T> 
T callFunc(T a, T b, F f) 
{ 
    return f(a, b); 
} 

Вы не можете просто написать

int a = callFunc(1, 2, sum); 

Вы должны написать

int a = callFunc(1, 2, sum<int>); 

Для пропуска sum без записи int, вы должны написать functor - struct или class с operator(), который вызовет вашу функцию шаблона. Тогда вы можете передать этот функтор в качестве аргумента шаблона. Вот пример.

template<class T> 
T sum(T a, T b) 
{ 
    return a + b; 
} 
template<class T> 
struct Summator 
{ 
    T operator()(T a, T b) 
    { 
     return sum<T>(a, b); 
    } 
}; 
template<template<typename> class TFunctor, class T> 
T doSomething(T a, T b) 
{ 
    return TFunctor<T>()(a, b); 
    //Equivalent to this: 
    //TFunctor<T> functor; 
    //return functor(a, b); 
} 


int main() 
{ 
    int n1 = 1; 
    int n2 = 2; 
    int n3 = doSomething<Summator>(n1, n2); //n3 == 3 
    return 0; 
} 
+0

Эта путаница не возникла бы в первую очередь, если бы люди использовали правильную терминологию: функции шаблона "не существуют, они являются" шаблонами функций ". То есть в вашем примере 'callFunc (1, 2, sum);' вы ** не ** передаете функцию 'callFunc', вы передаете ей * шаблон * (и, как показывает ваш пример, вы можете * * передавать шаблоны в качестве аргументов шаблона, но только шаблоны * class *, а не * function *). –

+0

Хм .. Не думал об этом таким образом. Я считаю, что исходный вопрос должен быть «Как передать шаблон функции в качестве аргумента шаблона функции», верно? – izogfif

+0

Итак, как бы вы сделали это решение, если сумма нестационарная член класса? –

1

Я использую лямбда для этого.

auto add = [](const auto& lhs, const auto& rhs) { 
    static_assert(std::is_arithmetic<typename std::decay<decltype(lhs)>::type>::value, 
      "Needs to be arithmetic."); 
    static_assert(std::is_arithmetic<typename std::decay<decltype(rhs)>::type>::value, 
      "Needs to be arithmetic."); 
    return lhs + rhs; 
}; 

template<typename LHS, typename RHS, typename FUNC 
    , typename OUT = typename std::result_of<FUNC(LHS, RHS)>::type> 
constexpr OUT do_arithmetic(LHS lhs, RHS rhs, FUNC func) { 
    return func(lhs, rhs); 
} 

constexpr auto t = do_arithmetic(40, 2, add); 
static_assert(t == 42, "Wrong answer!"); 
static_assert(std::is_same<std::decay<decltype(t)>::type, int>::value, 
     "Should be int.");