[英]C++: recursive member function template
我想使用 c++14 编写一个通用对象打印机。 这个想法是在任意包装的对象中搜索toString()
方法。 在这个例子中,它只理解指针间接获取可打印对象。
以下代码在 clang-8 上编译,但在 gcc-9 上失败:
#include <iostream>
#include <memory>
#include <string>
#include <boost/optional.hpp>
struct A {
std::string toString() const { return "gotchA"; }
};
struct Printer {
void print(const std::string &s) { std::cout << s << std::endl; }
template <typename T>
auto print(const T &o) -> std::enable_if_t<
std::is_same<decltype(o.toString()), std::string>::value> {
print(o.toString());
}
template <typename T> auto print(const T &o) -> decltype(this->print(*o));
};
template <typename T>
auto Printer::print(const T &o) -> decltype(this->print(*o)) {
print(*o);
}
int main() {
Printer{}.print(A{});
Printer{}.print(boost::make_optional(std::make_unique<A>()));
}
gcc 给出以下错误:
g++ -std=c++14 recursive.cpp
recursive.cpp:24:6: error: no declaration matches ‘decltype (((Printer*)this)->Printer::print((* o))) Printer::print(const T&)’
24 | auto Printer::print(const T &o) -> decltype(this->print(*o)) {
| ^~~~~~~
recursive.cpp:20:30: note: candidates are: ‘template<class T> decltype (((Printer*)this)->Printer::print((* o))) Printer::print(const T&)’
20 | template <typename T> auto print(const T &o) -> decltype(this->print(*o));
| ^~~~~
recursive.cpp:15:8: note: ‘template<class T> std::enable_if_t<std::is_same<decltype (o.toString()), std::__cxx11::basic_string<char> >::value> Printer::print(const T&)’
15 | auto print(const T &o) -> std::enable_if_t<
| ^~~~~
recursive.cpp:12:8: note: ‘void Printer::print(const string&)’
12 | void print(const std::string &s) { std::cout << s << std::endl; }
| ^~~~~
recursive.cpp:11:8: note: ‘struct Printer’ defined here
11 | struct Printer {
| ^~~~~~~
正如我在这些编译器输出行中看到的那样,候选与外部定义签名没有区别(除了开头的template
;添加了空格):
recursive.cpp:24:6: error: no declaration matches ‘decltype (((Printer*)this)->Printer::print((* o))) Printer::print(const T&)’
recursive.cpp:20:30: note: candidates are: ‘template<class T> decltype (((Printer*)this)->Printer::print((* o))) Printer::print(const T&)’
我如何实现递归? 我究竟做错了什么?
谢谢!
函数的名称不在其自己的声明符的范围内,包括任何trailing-return-type 。 因此,对重新声明的解释与原件的解释不同,因为原件随后可用。 相关规则并没有明确说明如何处理这样的情况:特别是,名称print
在技术上不是“依赖名称”(仅作为名称进行比较),因为它是类成员访问的一部分。 (如果是,则递归无论如何都不应该工作,因为只使用第一个声明中的查找。)
这里通常的方法是使用具有部分特化的类:
template<class> struct Printer;
template<class T>
void print(const T &t) {Printer<T>::go(t);}
template<class T,class=void>
struct Printer { // recursive case
void go(const T &t) {print(*t);}
};
template<>
struct Printer<std::string,void> {
void go(const std::string &s) { std::cout << s << std::endl; }
};
template<class T>
struct Printer<T,std::enable_if_t<
std::is_same<decltype(std::declval<T&>().toString()),
std::string>::value>> {
void go(const T &t) {print(t.toString());}
};
最后一个可能更好地仅以toString
的存在为条件,以便它可以利用递归支持。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.