SFINAE技术用于自由函数包装器

Mor*_*hai 2 c++ templates sfinae c++11 c++14

我真的希望能够有一个自由的功能,适应它给出的任何类型.

例如

template <typename T> bool ReadLine(T & reader, std::string & line) 
{
     return reader.ReadString(line); 
}
Run Code Online (Sandbox Code Playgroud)

对于某些T,正确的函数是reader.ReadString(缓冲区).但对于其他人来说,它应该是reader.ReadLine(缓冲区).当然,未来可能还有其他模式.关键是要使自由函数ReadLine(from,into)适应任何合理的from和into(我强制将目标缓冲区作为std :: string来简化这里的事情).

现在,我可以为我想要的任何具体类型创建一个非模板版本的ReadLine,但我真正需要的是能够部分专门化类型的类型,这样那些支持模式reader.ReadString()的东西都会结束使用它,以及那些支持reader.ReadLine()使用它,并在将来我可以添加其他模式,而不会打扰已经有效的任何东西.

我知道我可以创建一个策略类,例如LineReaderPolicy,它知道给定的T使用哪个模式(根据T将其部分专门化以将其映射到正确的模式.

但是有更好的,更多的C++ 14解决方法吗?

这是其中之一"上帝似乎模板真的非常接近于真正有用......但对于这个不断反复出现的问题..."

使用C++ 11/14,可堆性比以往任何时候都好,但似乎这个基本问题仍未得到解决?或者是它?!

您如何建议我编写一组适应任何合理T的自由函数来读取它的一行?是T是字符串流,输出迭代器,文件句柄,字符串,字符串视图等等...

我不能认为C++真的成熟了,直到我能写出一个合理的

template <typename T> size_t length(T t) { return t.size(); }
Run Code Online (Sandbox Code Playgroud)

为此,我可以将其扩展到任何合理的T,并且不必编写知道T的许多细节的代码,但可以通过这种灵活的自由功能适配器与大量的Ts互操作......

Cas*_*sey 8

如果您可以确保最多一个reader.ReadStringreader.ReadLine已定义,请使用SFINAE来控制重载(在Coliru实时):

template <typename T>
auto ReadLine(T& reader, std::string& line) -> decltype(reader.ReadString(line)) {
  return reader.ReadString(line); 
}

template <typename T>
auto ReadLine(T& reader, std::string& line) -> decltype(reader.ReadLine(line)) {
  return reader.ReadLine(line); 
}
Run Code Online (Sandbox Code Playgroud)

不适用的实现将触发SFINAE并从过载集中删除,只留下正确的实现.

在C++ 14中,您将能够省略尾随返回类型,并只使用返回类型推导.

在未来的C++版本中,Concepts Lite将使其更加干净.该区分两种不同的读者给出的概念-说StringReaderLineReader:

template <typename T>
concept bool StringReader() {
  return requires(T& reader, std::string& line) {
    {reader.ReadString(line)} -> bool;
  };
}

template <typename T>
concept bool LineReader() {
  return requires(T& reader, std::string& line) {
    {reader.ReadLine(line)} -> bool;
  };
}
Run Code Online (Sandbox Code Playgroud)

您将能够直接将您的实现约束到为这些概念建模的类型集:

bool ReadLine(StringReader& reader, std::string& line) {
  return reader.ReadString(line); 
}

bool ReadLine(LineReader& reader, std::string& line) {
  return reader.ReadLine(line); 
}
Run Code Online (Sandbox Code Playgroud)

希望你能够在其他地方重用这些概念,以证明"新特殊 - 更好"的语法比旧讨厌的语法长得多.Concepts Lite还可以处理通过显式消歧来模拟这两个概念的类型:

template <typename T>
  requires StringReader<T>() && LineReader<T>()
bool ReadLine(T& reader, std::string& line) {
  // Call one, or the other, or do something completely different.
}
Run Code Online (Sandbox Code Playgroud)

  • C++ 14返回类型推导确实_not_做SFINAE,设计,所以如果你想要SFINAE你需要保持trailing-return类型,或者将SFINAE移动到默认模板参数:`template <typename T,typename Requires = decltype(std :: declval <T&>().ReadString(std :: declval <std :: string&>()))> auto ReadLine(T&reader,std :: string&line){...}` (3认同)
  • @mordachai这个视觉工作室的失败被称为'缺乏对表达SFINAE的支持'. (2认同)