首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++:递归成员函数模板

C++:递归成员函数模板
EN

Stack Overflow用户
提问于 2019-12-21 10:33:32
回答 1查看 260关注 0票数 1

我想用c++14编写一个通用的对象打印机,其思想是在任意包装的对象中搜索toString()方法。在本例中,它只理解指针间接性以获得可打印对象。

以下代码在clang-8上编译,但在gcc-9上失败:

代码语言:javascript
复制
#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犯了以下错误:

代码语言:javascript
复制
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;添加了空格):

代码语言:javascript
复制
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&)’

如何实现递归?我做错了什么?

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-22 03:32:48

函数的名称在它自己的声明器中不在作用域中,包括任何尾部返回类型。因此,对重新声明的解释与原声明的解释不同,因为这样就可以获得原始声明。相关规则没有非常清楚地说明如何处理这种情况:特别是,名称print在技术上不是一个“依赖的名称”(仅作为名称进行比较),因为它是类成员访问的一部分。(如果是的话,递归无论如何也不能工作,因为只使用来自第一个声明的查找。)

这里通常的方法是使用具有部分专门化的类:

代码语言:javascript
复制
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的存在,这样它就可以利用递归支持。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59435419

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档