【问题标题】:template specialization for static member functions; howto?静态成员函数的模板特化;如何?
【发布时间】:2010-10-20 12:42:21
【问题描述】:

我正在尝试使用模板专业化来实现一个具有不同句柄的模板函数。

以下代码在 gcc 中为我提供了“非命名空间范围内的显式特化”:

template <typename T>
static T safeGuiCall(boost::function<T ()> _f)
{
    if (_f.empty())
        throw GuiException("Function pointer empty");
    {
        ThreadGuard g;
        T ret = _f();
        return ret;
    }
}

// template specialization for functions wit no return value
template <>
static void safeGuiCall<void>(boost::function<void ()> _f)
{
    if (_f.empty())
        throw GuiException("Function pointer empty");
    {
        ThreadGuard g;
        _f();
    }
}

我已尝试将其移出类(该类未模板化)并移入命名空间,但随后出现错误“显式专业化不能具有存储类”。我已经阅读了很多关于此的讨论,但人们似乎不同意如何专门化功能模板。有什么想法吗?

【问题讨论】:

    标签: c++ templates boost


    【解决方案1】:

    当你特化一个模板化方法时,你必须在类括号之外这样做:

    template <typename X> struct Test {}; // to simulate type dependency
    
    struct X // class declaration: only generic
    {
       template <typename T>
       static void f( Test<T> );
    };
    
    // template definition:
    template <typename T>
    void X::f( Test<T> ) {
       std::cout << "generic" << std::endl;
    }
    template <>
    inline void X::f<void>( Test<void> ) {
       std::cout << "specific" << std::endl;
    }
    
    int main()
    {
       Test<int> ti;
       Test<void> tv;
       X::f( ti ); // prints 'generic'
       X::f( tv ); // prints 'specific'
    }
    

    当你把它带出课堂时,你必须删除'static'关键字。类之外的静态关键字具有与您可能想要的不同的特定含义。

    template <typename X> struct Test {}; // to simulate type dependency
    
    template <typename T>
    void f( Test<T> ) {
       std::cout << "generic" << std::endl;
    }
    template <>
    void f<void>( Test<void> ) {
       std::cout << "specific" << std::endl;
    }
    
    int main()
    {
       Test<int> ti;
       Test<void> tv;
       f( ti ); // prints 'generic'
       f( tv ); // prints 'specific'
    }
    

    【讨论】:

    • hm 我现在尝试了同样的事情,但把它放在一个 .hpp 文件中并尝试包含它......然后我收到错误“vodi X:ff 的多重定义(测试)。我看不出有什么区别?
    • 是编译器还是链接器错误?如果这是一个编译器错误,则意味着您可能不止一次包含模板头,并且缺少头保护,因此双重定义:编译器看到了两个(唉,完全准确的)实现定义。
    • 为什么要为第一种情况添加内联?如果没有,我会收到编译错误。
    • @sop:我不确定第一种情况指的是什么...模板函数不需要inline,如果您将定义放在标题中,则模板专业化需要它(以避免ODR违规)
    • 关于专业;如果我将它从 header 移动到 .cpp(并且在 header 中仍然有模板),我仍然会收到多重定义的错误或
    【解决方案2】:

    这不是你问题的直接答案,但你可以写这个

    template <typename T>
    static T safeGuiCall(boost::function<T ()> _f)
    {
            if (_f.empty())
                    throw GuiException("Function pointer empty");
            {
                    ThreadGuard g;
                    return _f();
            }
    }
    

    即使 _f() 返回 'void' 也应该可以工作

    编辑:在更一般的情况下,我认为我们应该更喜欢函数重载而不是专业化。这是一个很好的解释:http://www.gotw.ca/publications/mill17.htm

    【讨论】:

      【解决方案3】:

      您可以像在其类之外定义成员函数一样声明显式特化:

      class A
      {
      public:
        template <typename T>
        static void foo () {}
      };
      
      template <>
      void A::foo<void> ()
      {
      }
      

      【讨论】:

      • 感谢您的回答。对我来说,他们是否在课堂上并不重要。但我不能让它工作。是我的语法错误还是我提供的代码有问题?
      • 关键是你在命名空间中使用一个合格的函数声明器明确地特化函数。 C++ 不允许您重新添加“静态”关键字,因此您只需将其删除。我上面的示例向您展示了如何显式专门化静态成员。
      【解决方案4】:

      您的问题似乎与 boost::function 有关 - 以下专业化工作:

      template <typename T>
      T safeGuiCall()
      {
          return T();
      }
      
      template <>
      void safeGuiCall<void>()
      {
      }
      
      int main() {
          int x = safeGuiCall<int>();     // ok
          //int z = safeGuiCall<void>();  // this should & does fail
          safeGuiCall<void>();            // ok
      }
      

      【讨论】:

      • 对不起,试过了,但没有用。你是在gcc下编译的吗?例如,我认为它可以在 VS 下工作...
      • 这是静态的 - 删除它们,一切都应该很好,它与 Comeau 一起编译,我会更新答案
      【解决方案5】:

      我遇到了类似的问题。如果您查看原始帖子,我将第一个静态留在其中,但取出了第二个,两个错误都消失了。

      【讨论】:

        猜你喜欢
        • 2013-05-30
        • 1970-01-01
        • 2012-10-02
        • 2016-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多