【问题标题】:Can a template parameter itself be templatized?模板参数本身可以模板化吗?
【发布时间】:2013-01-22 05:05:58
【问题描述】:

假设我有以下代码:

#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&lt;int, int, foo&gt; s;,而不是更好的S&lt;foo&gt; s;

是否可以将作为模板参数传递的函数模板化,这样我就可以做到S&lt;foo&gt; s;,而不是在S 中硬编码函数的返回类型和参数类型?

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

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

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

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

    【讨论】:

    • +1 喜欢使用 decltype。但是,不要叫它模板函数,叫它函数模板
    【解决方案2】:

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

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

    【讨论】:

    • 是的,我对间接函数调用的担心是对的……这段代码是超级计算机的模板元编程库。感谢标准的引用!
    【解决方案3】:

    这是不可能的。原则上与以下问题相同:您只想写A&lt;100&gt; 其中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 现在没有任何机会被内联。

    【讨论】:

      【解决方案4】:

      这对你有用吗?

      它可能不如 S&lt;foo&gt; 好,但在实例化时将参数保持为 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;
      }
      

      【讨论】:

      • o 不绑定到任何函数。 F 只知道函数的type,不知道function 本身。
      猜你喜欢
      • 1970-01-01
      • 2018-07-31
      • 1970-01-01
      • 2020-02-23
      • 2023-03-07
      • 2017-10-15
      • 1970-01-01
      • 2012-06-01
      • 2014-11-06
      相关资源
      最近更新 更多