C++ 模板专门化子类

C++ 模板专门化子类,c++,c++11,templates,inheritance,C++,C++11,Templates,Inheritance,我有一个问题,可以最小化到下面的例子 #include <iostream> #include <string> class A{ public: const char* chr; A(){chr = "aaa";} }; class B : A{ public: const char* chr; B(){chr = "bbb";} }; template <class T> std::string to_str

我有一个问题,可以最小化到下面的例子

#include <iostream>
#include <string>


class A{
  public:
    const char* chr;
    A(){chr = "aaa";}
};

class B : A{
  public:
    const char* chr;
    B(){chr = "bbb";}
};

template <class T>
std::string to_str(T) = delete;

template<>
inline std::string
to_str<A>(A object) {
    std::string str;
    return str.assign((object.chr));
}

int main() {
  A a;
  B b;
  std::cout << to_str(b) << std::endl;
}
#include <type_traits>
#include <iostream>
#include <string>

struct A     { char const * chr; A() : chr{"aaa"} {} };
struct B : A { char const * chr; B() : chr{"bbb"} {} };
struct C     { char const * chr; C() : chr{"ccc"} {} };    

template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
      to_str (T const & t)
 { return t.chr; }

int main()
 {
   A a;
   B b;
   C c;

   std::cout << to_str(a) << std::endl;    // print aaa
   std::cout << to_str(b) << std::endl;    // print bbb
   // std::cout << to_str(c) << std::endl; // compilation error
 }
现在让我们假设我有很多继承
a
的类,我能“告诉”编译器它们都可以去同一个函数(接受
a
的那个)吗

谢谢

我是否可以“告诉”编译器它们都可以指向同一个函数(接受A的函数)

是的,使用SFINAE和
std::是

template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
      to_str (T const & t)
 { return t.chr; }
模板
typename std::enable_if::type
to_街(施工及测试)
{返回t.chr;}
下面是一个完整的工作示例

#include <iostream>
#include <string>


class A{
  public:
    const char* chr;
    A(){chr = "aaa";}
};

class B : A{
  public:
    const char* chr;
    B(){chr = "bbb";}
};

template <class T>
std::string to_str(T) = delete;

template<>
inline std::string
to_str<A>(A object) {
    std::string str;
    return str.assign((object.chr));
}

int main() {
  A a;
  B b;
  std::cout << to_str(b) << std::endl;
}
#include <type_traits>
#include <iostream>
#include <string>

struct A     { char const * chr; A() : chr{"aaa"} {} };
struct B : A { char const * chr; B() : chr{"bbb"} {} };
struct C     { char const * chr; C() : chr{"ccc"} {} };    

template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
      to_str (T const & t)
 { return t.chr; }

int main()
 {
   A a;
   B b;
   C c;

   std::cout << to_str(a) << std::endl;    // print aaa
   std::cout << to_str(b) << std::endl;    // print bbb
   // std::cout << to_str(c) << std::endl; // compilation error
 }
#包括
#包括
#包括
结构A{char const*chr;A():chr{“aaa”}{};
结构B:A{char const*chr;B():chr{“bbb”}{};
结构C{char const*chr;C():chr{“ccc”}{};
样板
typename std::enable_if::type
to_街(施工及测试)
{返回t.chr;}
int main()
{
A A;
B B;
C C;
标准::cout
我是否可以“告诉”编译器它们都可以指向同一个函数(接受A的函数)

是的,使用SFINAE和
std::是

template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
      to_str (T const & t)
 { return t.chr; }
模板
typename std::enable_if::type
to_街(施工及测试)
{返回t.chr;}
下面是一个完整的工作示例

#include <iostream>
#include <string>


class A{
  public:
    const char* chr;
    A(){chr = "aaa";}
};

class B : A{
  public:
    const char* chr;
    B(){chr = "bbb";}
};

template <class T>
std::string to_str(T) = delete;

template<>
inline std::string
to_str<A>(A object) {
    std::string str;
    return str.assign((object.chr));
}

int main() {
  A a;
  B b;
  std::cout << to_str(b) << std::endl;
}
#include <type_traits>
#include <iostream>
#include <string>

struct A     { char const * chr; A() : chr{"aaa"} {} };
struct B : A { char const * chr; B() : chr{"bbb"} {} };
struct C     { char const * chr; C() : chr{"ccc"} {} };    

template <typename T>
typename std::enable_if<std::is_base_of<A, T>::value, std::string>::type
      to_str (T const & t)
 { return t.chr; }

int main()
 {
   A a;
   B b;
   C c;

   std::cout << to_str(a) << std::endl;    // print aaa
   std::cout << to_str(b) << std::endl;    // print bbb
   // std::cout << to_str(c) << std::endl; // compilation error
 }
#包括
#包括
#包括
结构A{char const*chr;A():chr{“aaa”}{};
结构B:A{char const*chr;B():chr{“bbb”}{};
结构C{char const*chr;C():chr{“ccc”}{};
样板
typename std::enable_if::type
to_街(施工及测试)
{返回t.chr;}
int main()
{
A A;
B B;
C C;
标准::cout
根据14.7.3[temp.expl.spec]第1段,只有未删除的功能模板可以明确专用

所以,如果你改变

template <class T>
std::string to_str(T) = delete;
模板
std::字符串to_str(T)=删除;
比如,

template <class T>
std::string to_str(T) { return ""; }
模板
std::字符串到_str(T){return”“;}
一切都应该正常

根据14.7.3[temp.expl.spec]第1段,只有未删除的功能模板可以明确专用

所以,如果你改变

template <class T>
std::string to_str(T) = delete;
模板
std::字符串to_str(T)=删除;
比如,

template <class T>
std::string to_str(T) { return ""; }
模板
std::字符串到_str(T){return”“;}

一切都应该正常

我怀疑这是否真的是你问题的一个最小化的例子。我认为发生的事情是一些重要的细节在翻译中丢失了,因为你在这里展示的代码有很多问题

  • B
    私下继承自
    A
    。在这种情况下,我们无法像对待
    A
    那样对待
    B
  • 如果您将继承更改为
    public
    ,那么我们可以尝试强制a
    B
    ,如下所示:

    class B : public A{/*...*/};
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
  • 下一个问题是,无法直接从
    A
    的实例恢复
    B
    chr
  • a
    中使用
    std::string
    成员,并且不要在任何派生类中重新声明它,那么派生类可以在初始化时设置它
  • 例如:

    class A{
      public:
        std::string chr;
        A():chr{"aaa"}{}
    };
    
    class B : public A{
      public:
        B(){chr = "bbb";}
    };  
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
        virtual const char* get_chr() const{return chr;}
    };
    
    class B : public A{
      public:
        const char* chr;
        B(){chr = "bbb";}
        const char* get_chr() const override {return chr;}
    };
    
    template <class T>
    std::string to_str(T) = delete;
    
    std::string to_str(A& object) {
        std::string str;
        return str.assign((object.get_chr()));
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
    #include <type_traits>
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
    };
    
    class B : A{
      public:
        const char* chr;
        B(){chr = "bbb";}
    };
    
    template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
    inline std::string to_str(T& object) {
        std::string str;
        return str.assign((object.chr));
    }
    
    int main() {
      A a;
      B b;
      std::cout << to_str(b) << std::endl;
    }
    
  • 我们在
    a
    中编写了一个
    virtual const char*get_char()
    方法,派生类可以覆盖该方法
  • 例如:

    class A{
      public:
        std::string chr;
        A():chr{"aaa"}{}
    };
    
    class B : public A{
      public:
        B(){chr = "bbb";}
    };  
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
        virtual const char* get_chr() const{return chr;}
    };
    
    class B : public A{
      public:
        const char* chr;
        B(){chr = "bbb";}
        const char* get_chr() const override {return chr;}
    };
    
    template <class T>
    std::string to_str(T) = delete;
    
    std::string to_str(A& object) {
        std::string str;
        return str.assign((object.get_chr()));
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
    #include <type_traits>
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
    };
    
    class B : A{
      public:
        const char* chr;
        B(){chr = "bbb";}
    };
    
    template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
    inline std::string to_str(T& object) {
        std::string str;
        return str.assign((object.chr));
    }
    
    int main() {
      A a;
      B b;
      std::cout << to_str(b) << std::endl;
    }
    
    总的来说,我认为最好的方法是给每个派生类在初始化时设置的
    A
    A
    protected std::string chr
    ,然后让专门用于
    A&
    (作为重载)的
    to_string
    函数打印该成员



    编辑:我忘了最后一个注意事项。#问题6:在
    A
    中没有
    virtual
    成员。因此,您将永远无法
    动态地将
    指向
    A
    的指针投射到任何派生类。

    我怀疑这是否真的是您问题的一个最小示例。我认为发生的是一些重要的细节ot在翻译过程中丢失了,因为您在这里向我们展示的代码有很多问题

  • B
    私下继承自
    A
    。在这种情况下,我们无法像对待
    A
    那样对待
    B
  • 如果您将继承更改为
    public
    ,那么我们可以尝试强制a
    B
    ,如下所示:

    class B : public A{/*...*/};
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
  • 下一个问题是,无法直接从
    A
    的实例恢复
    B
    chr
  • a
    中使用
    std::string
    成员,并且不要在任何派生类中重新声明它,那么派生类可以在初始化时设置它
  • 例如:

    class A{
      public:
        std::string chr;
        A():chr{"aaa"}{}
    };
    
    class B : public A{
      public:
        B(){chr = "bbb";}
    };  
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
        virtual const char* get_chr() const{return chr;}
    };
    
    class B : public A{
      public:
        const char* chr;
        B(){chr = "bbb";}
        const char* get_chr() const override {return chr;}
    };
    
    template <class T>
    std::string to_str(T) = delete;
    
    std::string to_str(A& object) {
        std::string str;
        return str.assign((object.get_chr()));
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
    #include <type_traits>
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
    };
    
    class B : A{
      public:
        const char* chr;
        B(){chr = "bbb";}
    };
    
    template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
    inline std::string to_str(T& object) {
        std::string str;
        return str.assign((object.chr));
    }
    
    int main() {
      A a;
      B b;
      std::cout << to_str(b) << std::endl;
    }
    
  • 我们在
    a
    中编写了一个
    virtual const char*get_char()
    方法,派生类可以覆盖该方法
  • 例如:

    class A{
      public:
        std::string chr;
        A():chr{"aaa"}{}
    };
    
    class B : public A{
      public:
        B(){chr = "bbb";}
    };  
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
        virtual const char* get_chr() const{return chr;}
    };
    
    class B : public A{
      public:
        const char* chr;
        B(){chr = "bbb";}
        const char* get_chr() const override {return chr;}
    };
    
    template <class T>
    std::string to_str(T) = delete;
    
    std::string to_str(A& object) {
        std::string str;
        return str.assign((object.get_chr()));
    // ...
    std::cout << to_str(*static_cast<A*>(&b)) << std::endl;
    
    #include <type_traits>
    
    class A{
      public:
        const char* chr;
        A(){chr = "aaa";}
    };
    
    class B : A{
      public:
        const char* chr;
        B(){chr = "bbb";}
    };
    
    template<class T, class = std::enable_if_t<std::is_base_of<A, T>::value, int>>
    inline std::string to_str(T& object) {
        std::string str;
        return str.assign((object.chr));
    }
    
    int main() {
      A a;
      B b;
      std::cout << to_str(b) << std::endl;
    }
    
    总的来说,我认为最好的方法是给每个派生类在初始化时设置的
    A
    A
    protected std::string chr
    ,然后让专门用于
    A&
    (作为重载)的
    to_string
    函数打印该成员



    编辑:我忘了最后一个注意事项。#问题6:在
    A
    中没有
    virtual
    成员。因此,您将永远无法
    动态地将
    指向
    A
    的指针投射到任何派生类。

    模板函数专门化不是这样工作的。没有重载解析;它只允许替换指定的具有特定模板参数的ic函数体与您的专用函数体。它很少有用

    您需要的是重载解析,可能是标记分派

    首先,完全删除此选项:

    template <class T>
    std::string to_str(T) = delete;
    
    过载解析将
    B
    发送到
    A
    过载

    下一个问题是切片。
    B
    有两个名为
    chr
    的成员:
    A::chr
    B::chr
    。没有充分的理由。此外,您不必要地复制
    A
    (或
    B
    A
    子对象)

    这个av