Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 用于自由函数包装器的SFINAE技术_C++_Templates_C++11_Sfinae_C++14 - Fatal编程技术网

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

C++ 用于自由函数包装器的SFINAE技术,c++,templates,c++11,sfinae,c++14,C++,Templates,C++11,Sfinae,C++14,我真的希望能够有一个自由的功能,适应任何类型的被赋予 e、 g 模板bool ReadLine(T&reader,std::string&line) { 返回reader.ReadString(第行); } 对于某些T,正确的函数是reader.ReadString(缓冲区)。但对于其他人,它应该是reader.ReadLine(缓冲区)。当然,未来可能还有其他模式。重点是调整自由函数ReadLine(from,into)以使用任何合理的from&into集(我已强制目标缓冲区为std::st

我真的希望能够有一个自由的功能,适应任何类型的被赋予

e、 g

模板bool ReadLine(T&reader,std::string&line)
{
返回reader.ReadString(第行);
}
对于某些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(); }
template <typename T> size_t length(T t) { return t.size(); }
template size_t length(tt){return t.size();}

为此,我可以将其扩展到任何合理的T,不再需要编写了解T的许多细节的代码,但可以通过这种灵活的免费函数适配器与成吨的T进行交互操作…

如果您可以确保最多定义一个
reader.ReadString
reader.ReadLine
,请使用SFINAE来控制加载():

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

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

bool ReadLine(LineReader& reader, std::string& line) {
  return reader.ReadLine(line); 
}
希望您能够在其他地方重用这些概念,以证明“新的特殊更好”语法比旧的讨厌语法长得多。概念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.
}
模板
需要StringReader()&&LineReader()
bool ReadLine(T&reader,std::string&line){
//给其中一个打电话,或者做一些完全不同的事情。
}
我不能认为C++是真正成熟的,直到我能写出一个合理的<
template <typename T> size_t length(T t) { return t.size(); }
template <typename T> size_t length(T t) { return t.size(); }
template size_t length(tt){return t.size();}
为此,我可以将其扩展到任何合理的T中,不再需要编写了解T的许多细节的代码,但可以通过这种灵活的自由函数适配器与大量的T进行交互操作

您需要概念Lite,我希望它能在C++17中实现:

template<typename T>
  concept bool Has_size()
  {
    return requires(T t) {
      t.size() -> Integral;
    };
  }

template<typename T>
  concept bool Has_length()
  {
    return requires(T t) {
      t.length() -> Integral;
    };
  }

template <Has_size T> auto length(T t) { return t.size(); }
template <Has_length T> auto length(T t) { return t.length(); }
模板
概念bool具有_尺寸()
{
返回要求(T){
t、 size()->积分;
};
}
模板
概念布尔有_长度()
{
返回要求(T){
t、 长度()->积分;
};
}
模板自动长度(T){返回T.size();}
模板自动长度(T){返回T.length();}
在此之前,您可以使用SFINAE来模拟它,这可以通过多种方式完成,您的示例中最简洁的可能只是一个尾随返回类型,如Casey的回答所示

template <typename T>
  auto length(T t) -> decltype(t.size()) { return t.size(); }
template <typename T>
  auto length(T t) -> decltype(t.length()) { return t.length(); }
模板
自动长度(T)->decltype(T.size()){return T.size();}
模板
自动长度(T)->decltype(T.length()){return T.length();}

这种技术可以让您拥有复杂的测试和方法体。您基本上必须手动执行重载解析和分派,但它提供了完全的控制。它类似于
std
算法用来分派迭代器类型的技术:在这种情况下,不仅仅是
true\u类型
false\u类型
是d发布日期。

您能否详细说明为什么要创建策略类(函数可以委托给该类)还不足以满足您的需要?策略类确实有效。我只是…希望它不是必需的。我希望有一种更好的方法-少一些语法上的混乱,更直接地表达所需的变化。还有…策略如何真正解决理想情况下,编译器应该选择适合的,不多也不少。“例如,如果我可以只提供代码模式,而编译器尝试了每一种模式并使用了任何非含糊工作的模式,那将比为每一个可能的T实现多个策略要好得多。我甚至不知道如何使策略类真正比完全专用的自由函数+默认模板函数做得更好。。。“t.ReadString(buffer)。但对于其他人来说,它应该是s.ReadLine(buffer)”…我想你是指
reader.ReadString(line)
?阅读第一段时,我感到非常困惑,想知道所有这些新变量是从哪里来的。对此感到抱歉:(C++14返回类型推断在设计上不支持SFINAE,因此如果希望使用SFINAE,则需要保留尾随返回类型,或将SFINAE移动到默认模板参数:
template auto ReadLine(T&reader,std::string&line){…}
@JonathanWakely感谢您的更正。在发布答案后,我立即对该断言进行了重新思考,我一直在浏览N3936试图支持它。建议中写道:“SFINAE:由于返回类型是通过实例化模板推导出来的,如果实例化不适合
template <typename T>
  auto length(T t) -> decltype(t.size()) { return t.size(); }
template <typename T>
  auto length(T t) -> decltype(t.length()) { return t.length(); }
template<typename>struct type_sink{typedef void type;};
template<typename T>using TypeSink=typename type_sink<T>::type;
template<typename T,typename=void>
struct has_x:std::false_type{};
template<typename T>
struct has_x<T,TypeSink(decltype(std::declval<T>().x())>:std::true_type{};
template<typename T>
bool do_x_helper(T&t, std::true_type ){
  return t.x();
}
template<typename T>
bool do_x_helper(T7, std::false_type ){
  // alternative
}
template<typename T>
bool do_x(T& t){
  return do_x_helper( t, has_x<T>() );
}