用于泛型类型上的泛型操作的SFINAE
SFINAE for generic operation on generic type
我有
-
一个类Value,它可以用不同的类型(Foo,Bar,int,…)构造。
-
classValue应该具有类似<lt;,==<,。。。以底层类型进行
-
我添加了运算符<lt外部类定义。
我必须使用以下代码:
#include <iostream>
struct Foo {
};
struct Bar {
};
struct Value {
template<typename T>
Value(T) {
}
};
std::ostream &operator<<(std::ostream &os, const Bar &) {
return os << "Barn";
}
std::ostream &operator<<(std::ostream &os, const Value &value) {
auto visitor = [&](auto a) -> decltype(os << a) {
return os << a;
};
// Works
visitor(Bar{});
// Infinity call of this function with Value.
visitor(Foo{});
return os;
}
int main() {
std::cout << Value(1);
return 0;
}
活生生的例子。
问题是:如果底层类型没有实现运算符<lt;,运算符<lt;从值被称为递归无穷大。我想得到一个编译器错误,比如调用运算符<lt;(std:ostream&,const-Value&)将SFINAE用于我的访问者模式(此处未显示)。
我需要的是:
[&](auto a) -> std::enable_if_t<addressof?(os << a) != addressof?(os << Value{})>::value> {
return os << a;
};
如果函数相同,则禁用此lambda。这可能吗?
没有价值的解决方案:
- 使值显式
- 禁用Foo的Value构造
您可以添加一个包装器来强制执行一个转换:
template <typename T>
struct OneConversion
{
OneConversion(const T& t) : t(t) {}
operator const T&() const {return t;}
const T& t;
};
template <typename T>
struct isOneConversion : std::false_type {};
template <typename T>
struct isOneConversion<OneConversion<T>> : std::true_type {};
struct Value {
template<typename T, std::enable_if_t<!isOneConversion<T>::value>* = nullptr>
Value(T) {}
};
std::ostream &operator<<(std::ostream &os, const Value &value) {
auto visitor = [&](auto a) -> decltype(os << OneConversion<decltype(a)>(a)) {
return os << OneConversion<decltype(a)>(a);
};
// Works
visitor(Bar{});
visitor(Foo{}); // Error as expected.
return os;
}
演示
在不修改std::ostream &operator<<(std::ostream &os, const Value &value)
的签名的情况下,我们可以检查为a
在lambda中被推导为的类型调用operator<<
的尝试是否格式正确:
auto visitor = [&](auto a) -> decltype(
static_cast<std::ostream&(*)(std::ostream&, const decltype(a)&)>(&operator<<)
(os, a)
)
{
return os << a;
};
与Bar
一起工作,与Foo
一起失败,并显示错误消息:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'std::ostream& (*)(std::ostream&, const Foo&
Demo
您可以替换
std::ostream &operator<<(std::ostream &os, const Value &value)
{
// ...
}
带有
template <typename T, typename = std::enable_if_t<std::is_same_v<T, Value>>>
std::ostream &operator<<(std::ostream &os, const T &value)
{
// ...
}
您仍然可以使用它打印Value
对象,但不需要隐式转换。
将它放入您的代码中会导致它在visitor(Foo{});
失败,并出现以下错误,这似乎正是您想要的。
... main.cpp:29:12: error: no match for call to '(operator<<(std::ostream&, const T&) [with T = Value; <template-parameter-1-2> = void; std::ostream = std::basic_ostream<char>]::<lambda(auto:1)>) (Foo)' visitor(Foo{}); ~~~~~~~^~~~~~~ ...
相关文章:
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 重载操作程序时出错>>用于类中的字符串 memebr
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- 对字符串进行位操作
- 我可以在 C++ 中的函数体之外进行操作吗?
- MPI突然停止了对多个核心的操作
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 对字符数组中的元素执行逐位操作
- 如何在directx/c++中进行平移/缩放操作
- 逐位操作的隐式类型转换
- 为什么一个向量上的多线程操作很慢
- 提供与TMP和SFINAE的通用接口
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- "Inverse SFINAE"避免模棱两可的过载
- 位移操作和位掩码未检测到重复字符
- 用于泛型类型上的泛型操作的SFINAE