我想用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&)’如何实现递归?我做错了什么?
谢谢!
发布于 2019-12-22 03:32:48
函数的名称在它自己的声明器中不在作用域中,包括任何尾部返回类型。因此,对重新声明的解释与原声明的解释不同,因为这样就可以获得原始声明。相关规则没有非常清楚地说明如何处理这种情况:特别是,名称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的存在,这样它就可以利用递归支持。
https://stackoverflow.com/questions/59435419
复制相似问题