【问题标题】:Explicit template specialization cannot have a storage class - member method specialization显式模板特化不能有存储类-成员方法特化
【发布时间】:2015-03-13 20:55:49
【问题描述】:

假设我在 Visual Studio 中有以下代码

class foo
{
public:
    template<typename t>
    void foo_temp(int a , t s_)
    {
        std::cout << "This is general tmeplate method";
    }

    template<>
    static void foo_temp(int a , int s)
    {
        std::cout << "This is a specialized method";
    }
};


int main()
{
    foo f;
    f.foo_temp<std::string>(12,"string");
}

现在我正试图将其转换为 GCC。通过关于 SO 的其他问题,我注意到如果类不是专门的,则在 GCC 成员方法中不能专门化。因此我想出了这个解决方案

class foo
{

    public:
    template<typename t>
    void foo_temp(int a , t s_)
    {
        std::cout << "This is general template method";
    }


};

template <>
/*static*/ void foo::foo_temp<int>(int a, int value) {
    std::cout << "Hello world";
}

现在这似乎可以解决问题,但是当我在语句中包含 static 关键字时,我得到了错误

 explicit template specialization cannot have a storage class

现在this 线程谈论它,但我仍然对如何在这里应用它感到困惑。关于如何使最后一个方法成为静态的任何建议?此外,我仍然对为什么 GCC 中的模板方法不能是静态的感到困惑?

这是视觉工作室代码

class foo
{
public:
    template<typename t>
    void foo_temp(int a , t s_)
    {
        std::cout << "This is general tmeplate method";
    }

    template<>
    static void foo_temp(int a , int s)
    {
        std::cout << "This is a specialized method";
    }
};


int main()
{
    foo f;
    f.foo_temp<std::string>(12,"string");
}

【问题讨论】:

  • 你为什么要这样做?
  • 我正在移植一个代码,它不像我提出的那样简单。
  • 说真的,在 MSVC 中编译的原始代码??!我知道它的模板引擎非常不合格,但这是一个新低。
  • @T.C.是的,VS2013 没有任何抱怨。我将foo::foo_temp(12,12); 添加到main(),但仍然没有。甚至第二个 sn-p 也被接受,static 等等,但我必须将其称为 f.foo_temp(12,12);
  • @Praetorian 哇。哇。

标签: c++


【解决方案1】:

关于如何使最后一个方法成为静态的任何建议?

你不能;语言不支持。

另外,我仍然对为什么 GCC 中的模板化方法不能是静态的感到困惑?

他们可以;它们不能既是静态的又是非静态的。示例:

struct foo {
  template<typename T>
  void bar() {}

  template<typename T>
  static void baz() {}
};

int main() {
  foo f;
  f.template bar<void>();
  foo::baz<void>();
}

我很困惑为什么你必须有一个(非静态)模板成员函数的静态特化。我会认真地重新评估这段代码的完整性。

注意,对于 cmets 中的问题,不可能对静态成员函数进行模板特化,因为在这种情况下根本不可能对成员函数进行模板特化。 (改用重载。)

struct foo {
  template<typename T, typename U>
  static void bar(T, U) {}

  // Error, you'd need to also specialize the class, which requires a template class, we don't have one.
  // template<>
  // static void bar(int, int) {}
  // test.cpp:2:12: error: explicit specialization of non-template ‘foo’
  //     2 | struct foo {
  //       |            ^
  
  // Partial specializations aren't allowed even in situations where full ones are
  // template<typename U>
  // static void bar<int, U>(int, U) {}
  // test.cpp:14:33: error: non-class, non-variable partial specialization ‘bar<int, U>’ is not allowed
  //   14 |   static void bar<int, U>(int, U) {}
  //      |                                 ^

  // Instead just overload
  template<typename U>
  static void bar(int, U) {}
};

【讨论】:

  • 我很困惑为什么专门化静态方法是个坏主意。我遇到了一个类似的问题,我的实用程序在一个静态类中,我想用某种类型专门化其中一个,这种类型不适用于非专业化方法。当然,命名空间或 constexpr ifs 将提供解决方法,但专业化仍然会更干净......?
  • 这是一个观点,我想我在 5 年前就已经说过了。但我仍然认为这是一个坏主意。模板的重点是为一个类提供一个统一的 API,而不管其类型如何。如果您有一个具有相同功能但基于类型具有不同 API 的类的版本,这会让人感到困惑并削弱模板的实用性。话虽这么说,这也有一个技术原因,它不会发生,它与成员函数在内部是如何实现的有关。非静态成员函数作为其第一个参数传递给实例,而静态成员函数不会。
  • 我已经更新了答案,也许可以更好地解决您的问题@NormanPellet
  • 啊,是的,很公平!我总是忘记成员函数专业化的这个非常严格的限制。
【解决方案2】:

你尝试过老式的重载吗?根本不要将静态方法作为模板,而让重载优先级负责挑选它。

【讨论】:

    【解决方案3】:

    这里的静态方法不是问题,类中的template&lt;&gt; 声明是罪魁祸首。您不能在类中声明专门的模板。你可以改用命名空间:

    namespace foo{
    
            template<typename t>
            void foo_temp(int a , t s_)
            {
                std::cout << "This is general tmeplate method";
            }
            template<>
              void foo_temp(int a , int s)
            {
                std::cout << "This is a specialized method";
            }
    
        }
    
    
    
    
        int main()
        {
    
            foo::foo_temp<int>(12,7);
        }
    

    或者你可以像这样在类中使用它:

    class foo
    {
    public:
        template<typename t>
        void foo_temp(int a , t s_)
        {
            std::cout << "This is general tmeplate method";
        }
    
    
        static void foo_temp(int a , int s)
        {
            std::cout << "This is a specialized method";
        }
    };
    
    
    int main()
    {
        foo f;
        f.foo_temp(12,"string");
        f.foo_temp(12,6);
    }
    

    注意:在这种情况下,您应该像 f.foo_temp(a,b) 一样调用这两个函数(至少是第二个函数)而不是 f.foo_temp&lt;int&gt;()

    【讨论】:

      猜你喜欢
      • 2015-03-04
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多