C++ 继承成员函数的模板专门化

C++ 继承成员函数的模板专门化,c++,templates,C++,Templates,我们想专门化基类的成员函数。但是,它不编译。有人知道有什么替代方案可以编译吗 这里有一个例子 struct Base { template<typename T> void Foo() { throw "Foo() is not defined for this type"; } }; struct Derived : public Base { template<> void Foo<int>

我们想专门化基类的成员函数。但是,它不编译。有人知道有什么替代方案可以编译吗

这里有一个例子

struct Base
{
    template<typename T>
    void Foo()
    {
        throw "Foo() is not defined for this type";
    }
};

struct Derived : public Base
{
    template<>
    void Foo<int>() { cout << "Foo<int>()" << endl; } // compile error (cannot specialize members from a base class)

    template<>
    void Foo<double>() { cout << "Foo<double>()" << endl; }  // compile error (cannot specialize members from a base class)
};
struct Base
{
模板
void Foo()
{
抛出“未为此类型定义Foo()”;
}
};
结构派生:公共基
{
模板

void Foo(){cout这将编译,除了调用
Foo()


最终,我们使用重载解决了这个问题

下面是基类的外观

struct Base
{
    template<typename T>
    class OfType {}

    template<typename T>
    void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); }
};

struct Derived : public Base
{
    using Base::Foo;

    void Foo(OfType<int>) { // here comes logic for ints }
    void Foo(OfType<double>) { // here comes logic for doubles }
};

针对与Alex的讨论(参见John Dibling回答的评论),我的意思是(SSCCE):

#包括
使用名称空间std;
结构基
{
模板
void Foo()
{
//静态_断言(false,“未为此类型定义Foo());
抛出“未为此类型定义Foo()”;
}
};
//您可以在Base中添加任意数量的专门化
模板

void Base::Foo(){是否将不会有多态行为返回到基,并且您无法使模板函数虚拟。不确定您试图实现什么。我们正在尝试创建具有专用成员的工厂类,并且我们希望在不知道如何处理方法未专用的类型时引发异常。我们希望在我们的示例中,h可以创建许多类似于派生类的类。否则,我们就不会有基类。与其在运行时抛出异常,不如在编译时失败。派生的.Foo不会抛出。它只是不编译(链接错误)。此外,我们将无法使用包含更多专门化的DerivedMore扩展派生类。还有其他想法吗?@Alex:您可以简单地为
Derived::Foo
return Base::Foo()添加默认实现
@DyP:我们可以,但这意味着我们必须在每个派生类型中添加它。如果我有很多这样的派生类型会怎么样?@Alex:我不太明白。如果你的派生类有专门的工厂方法,那么你在每个派生类型中都已经有了
Foo
函数。如果派生类型没有添加专门化,你甚至没有o提供
Foo
方法(从基类继承)@DyP:这就是我想要的。但是正如我所说的,上面的示例没有编译。为了编译,我们需要在每个派生类型中重新实现默认的Foo。但是为什么要抛出它呢?如果它只是不编译就更好了。你是对的。我会将其更改为静态断言,或者将其全部删除。无论如何,上面的加载允许我创建派生类的层次结构。专门化不允许我这样做。顺便说一句,编译器错误比链接错误更好,它会告诉您在代码中的何处使用坏重载,而不仅仅是它不存在(您知道).main返回int not void,当您抛出异常时,抛出从std::exception派生的异常。您不能使用多态性从基调用专用方法,那么重点是什么?
template<typename T> 
void Derived::Foo() { cout << "generic" << endl; }
struct Base
{
    template<typename T>
    class OfType {}

    template<typename T>
    void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); }
};

struct Derived : public Base
{
    using Base::Foo;

    void Foo(OfType<int>) { // here comes logic for ints }
    void Foo(OfType<double>) { // here comes logic for doubles }
};
template<typename S>
class ClassThatUsesFoo
{
    private: S s;

    template<typename T>
    void Bar(T item) 
    {  
        s.Foo(Base::OfType<T>());  // this is the code that uses Foo
        DoSomeStuffWithItem(item); 
    } 
};

void main()
{
    ClassThatUsesFoo<Derived> baz;
    baz.Bar(12); // this will internally use Foo for ints
    baz.Bar(12.0); // this will use Foo for doubles
    baz.Bar("hello world"); // this will give a verbose compile error
}
#include <iostream>
using namespace std;

struct Base
{
    template<typename T>
    void Foo()
    {
        //static_assert(false, "Foo() is not defined for this type");
        throw "Foo() is not defined for this type";
    }
};
    // you can add as many specializations in Base as you like
    template <>
    void Base::Foo<char>()  {  cout << "Base::Foo<char>()" << endl;  }


struct Derived : public Base
{
    // just provide a default implementation of Derived::Foo
    // that redirects the call to the hidden Base::Foo
    template < typename T >
    void Foo()
    {  Base::Foo<T>();  }
};
    // the specializations for Derived
    template<>
    void Derived::Foo<int>() { cout << "Foo<int>()" << endl; }

    template<>
    void Derived::Foo<double>() { cout << "Foo<double>()" << endl; }


struct Derived_wo_specialization : public Base
{
    /* nothing */
};


int main()
{
    Derived d;
    d.Foo<char>();
    d.Foo<double>();

    Derived_wo_specialization dws;
    dws.Foo<char>();
    dws.Foo<double>();
}