4

假设我有以下代码:

#include <iostream>
#include <functional>

template <int func(int)>
struct S : std::unary_function<int, int>
{
    int operator()(int x) const
    {
        return func(x);
    }
};

int foo(int x)
{
    return x;
}

int main()
{
    S<foo> s;

    std::cout << s(42) << std::endl;
}

这可以作为将函数包装在函子内的一种方式,这意味着它可以在其他模板化函数中使用(例如sort,例如(假设函子具有正确的签名))。我不想为每种可能的返回/参数类型创建一个仿函数结构(实际上我不能),所以我尝试了以下方法:

template <template <typename R, // Make the return type and argument type template parameters!
                    typename A> R func(A)>
struct S : std::unary_function<R, A>
{
    R operator()(A arg) const
    {
        return func(arg);
    }
};

那没有用;它给了我编译错误。所以我尝试了:

template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
    R operator()(A arg) const
    {
        return func(arg);
    }
};

哪个起作用。不幸的是,我不得不将实例更改S为 beS<int, int, foo> s;而不是 nicer S<foo> s;

是否有可能将作为模板参数传递的函数模板化,这样我就可以做到S<foo> s;而不是硬编码函数的返回类型和参数类型S

我的 google-foo 无法找到具体的答案。

编辑:现在我想知道这是否不可能。我只是想到“如果foo是重载函数怎么办?” 据我所知,没有一种方法可以知道在说时使用哪种方法, 因此需要明确说明返回/参数类型。这是正确的想法吗?这是否意味着我的第一个问题的答案是“不,这不可能”?fooS<foo> s;

4

4 回答 4

3

不幸的是,我认为这是防止传递函数进行必要转换的唯一方法。但是您可以添加函数模板来帮助您推断(1) 函数 args (2) 函数返回的类型,如下面的代码:

template < typename R, typename A >
R result_of( R(A) );

template < typename R, typename A >
A arg0_of( R(A) );

然后您可以使用它们来构造想要的函数对象并让编译器进行可能的优化

#define get_call( f ) call_t< decltype(result_of(f)), \
                              decltype(arg0_of(f)), f >()

// same as the class 'S'
template < typename R, typename A,
           R unary( A ) >
struct call_t : std::unary_function<A,R> {
    R operator()( A arg ) const {
        return unary( arg );
    }
};

使用实用程序:

int neg( int arg ) {
    return -arg;
}

auto s = get_call( neg );
cout << s( 1 ) << endl;  // outputs: -1

它也适用于功能模板。当然,您必须将参数传递给模板:

template < typename T >
T square( T arg ) {
    return arg * arg;
}

template <>
int square( int arg ) {
   cout << "square<int>()" << endl;
   return arg * arg;
}

auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
                          //          144

编辑:对于重载函数,您可以进行转换以告诉编译器您要调用哪个版本:

int cube( int arg ) {
    return arg * arg * arg;
}

float cube( float arg ) {
    return arg * arg * arg;
}

typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000
于 2013-01-22T13:07:14.913 回答
2

您似乎想要一个非类型模板模板参数。但是,模板模板参数的唯一合法语法是template < template-parameters > class. (“模板模板参数的模板参数应是类模板或别名模板的名称,表示为 id-expression。”§ 14.3.3)

您可以创建一个模板类,其构造函数参数是函数指针,但我猜您担心会创建间接函数调用。

于 2013-01-22T05:30:38.090 回答
2

这是不可能的。原则上与以下问题相同:您希望仅A<100>将 whereA定义为:

template<T N>
struct A {};

给定N的是100T原来是int。美好的。这可以由人脑推断,但编译器不能推断,即使它们 100% 符合 C++11 标准。我在这里有完全相同的问题:

--

所以我认为的替代解决方案是:

template <typename R, typename A>
struct S : std::unary_function<R, A>
{
    typedef R (*Fun)(A);
    Fun func;
    S(Fun f) : func(f) {}
    R operator()(A arg) const
    {
        return func(arg);
    }
};

然后将MakeS函数定义为:

template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A)) 
{  
    return S<R,A>(fun); 
}

您可以将其用作:

auto s = MakeS(foo);

或者,简单地说:

S<int,int> s(foo);

这种替代方案的缺点是该函数foo现在没有任何内联的机会。

于 2013-01-22T05:49:21.207 回答
0

这对你有用吗?

它可能不如S<foo>但在实例化时将参数保持为 1。

int f(int) { return 0; }


template<class R, class A> struct S
{
    typedef R(*FTYPE)(A);
    typedef R RET;
    typedef A ARG;
};

template<class R, class A> S<R, A> FW(R(f)(A));

template<class T> struct F  : std::unary_function<typename T::RET, typename T::ARG>
{

};

int main()
{
    F<decltype(FW(f))> o;
}
于 2013-01-22T06:29:58.323 回答