繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM