2013-01-22 57 views
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); 
    } 
}; 

那没有工作; it gave me compilation errors。于是我尝试:

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

其中工作。不幸的是,我不得不将S的实例更改为S<int, int, foo> s;而不是更好的S<foo> s;

是它在所有可能的模板化的模板参数,这样我可以做S<foo> s;,而不是硬编码在S函数的返回类型和参数类型传递的功能?

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

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

回答

2

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

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

+0

是的,你对我的间接函数调用的担心是正确的...这个代码是超级计算机的模板元编程库。感谢标准的报价! – Cornstalks

2

这是不可能的。这是原则下一个同样的问题:你希望写只是A<100>其中A被定义为:

template<T N> 
struct A {}; 

鉴于N100T原来是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没有现在被内联任何机会。

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; 
} 
+0

'o'不绑定到任何函数。 'F'只知道函数的*类型*,而不知道函数*本身。 – Nawaz

3

不幸的是,我认为这是阻止传递函数进行必要转换的唯一方法。 但是你可以添加功能模板,帮助您推断类型的(1)函数参数(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 

它也适用于函数模板。当然,你必须通过参数(S)为模板:

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 
+0

+1喜欢使用decltype。但是,不要将其称为*模板函数*,将其称为*函数模板*。 – Nawaz

+0

感谢您的建议:) –

相关问题