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
,那么我们可以尝试强制aB
,如下所示:
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
Aprotected std::string chr
,然后让专门用于A&
(作为重载)的to_string
函数打印该成员
编辑:我忘了最后一个注意事项。#问题6:在A
中没有virtual
成员。因此,您将永远无法动态地将指向A
的指针投射到任何派生类。我怀疑这是否真的是您问题的一个最小示例。我认为发生的是一些重要的细节ot在翻译过程中丢失了,因为您在这里向我们展示的代码有很多问题
B
私下继承自A
。在这种情况下,我们无法像对待A
那样对待B
如果您将继承更改为public
,那么我们可以尝试强制aB
,如下所示:
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
Aprotected 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