fun*_*run 5 c++ templates sfinae c++17
我正在尝试学习如何使用 SFINAE。出于练习目的,我试图制作一个std::ostream包装器以制作自定义格式化程序。
这是我的 SFINAE 和自定义输出类。
// Tester
template <class O>
struct is_ostreamable {
template <class T>
static auto check(T t) -> decltype(std::declval<std::ostream &>() << t, std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
// Custom class
struct CustomOutput {
// Constructor etc...
CustomOutput(std::ostream &os = std::cout) : os{os} {}
std::ostream &os;
// Problematic template function
template <class O, class = std::enable_if_t<is_ostreamable<O>::value>>
CustomOutput &operator<<(O o) {
os << o;
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
完全不启用模板struct或class无法通过operator<<. 但是,有了这个 SFINAE,ostream 操纵器就不起作用了……我不知道为什么。
错误,以及我的期望:
int main(void){
CustomOutput{} << "hi"; // Fine
std::vector<int> vec;
// CustomOutput{} << vec; // Error. Expected
CustomOutput{} << std::endl; // Error. WHY?
}
Run Code Online (Sandbox Code Playgroud)
也许我错过了什么?任何帮助将不胜感激。
首先,调整你的ostreamable班级。目前,您的类需要T可从0. 许多班级的情况并非如此。它应该用来std::declval创造价值:
template <class O>
struct is_ostreamable {
template <class T>
static auto check(int) -> decltype(std::declval<std::ostream &>() << std::declval<T>(), std::true_type());
template <class>
static auto check(...) -> std::false_type;
public:
static constexpr bool value{std::is_same_v<decltype(check<O>(0)), std::true_type>};
};
Run Code Online (Sandbox Code Playgroud)
这里做了两处修改:
操作数decltype用于std::declval<T>()创建类型 的对象T。 std::declval<T>是一个(故意未定义的)函数模板,T在未计算的操作数(例如 to decltype、 or sizeof、noexcept运算符等)中使用时生成类型的对象,而不依赖于特定的构造签名(在您的情况下是复制构造0)。
参数 tocheck替换为int。value变量的初始化程序check使用参数进行调用0,因此该int参数确保(int)排名高于(...)重载决策中的排名,以便true_type在可能的情况下选择重载。
std::endl您需要为函数式操纵器( 、等)提供特殊的重载std::flush:
using manip = std::ostream& (*)(std::ostream&);
CustomOutput& operator<<(manip m) {
os << m;
return *this;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,没有办法让通用模板版本支持此功能。这是因为std::endl是一个函数模板:
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& endl(td::basic_ostream<CharT, Traits>& os);
Run Code Online (Sandbox Code Playgroud)
对于要使用的函数模板,必须确定适当的模板参数。不可能将类型模板参数推导T为通用模板。
不管怎样,这可能是您需要的唯一特殊重载。
| 归档时间: |
|
| 查看次数: |
133 次 |
| 最近记录: |