检查 operator() 是否存在
Check existence of operator()
我需要一个类型特征 HasCall 来检查 T 的以下类型实例化的有效性:
template<class T> struct Caller: T
{
using T::operator();
};
有没有办法在 C++14 中做到这一点?
这是我的尝试,但它不起作用:
https://godbolt.org/z/vxgJCR
编辑
我知道 SFINAE 及其运作方式。这个问题比仅仅检查某些表达式的有效性更困难。
我希望这些断言通过:
struct A {void operator()(int) {}};
static_assert(HasCall<A>, "Check must work with any set of arguments.");
struct B {void operator()() {}};
static_assert(HasCall<B>, "Check must work with any set of arguments.");
struct C {template<typename... Args> void operator()(Args&&...) {}};
static_assert(HasCall<C>, "Templated operators must be detected correctly.");
struct D {};
static_assert(!HasCall<D>, "No operator() at all.");
static_assert(!HasCall<void(*)()>, "Class cannot inherit from function pointers.");
检查表达式 &T::operator() 的有效性是不够的,因为它不适用于重载或模板 operator()。
请使用这些断言检查您的解决方案。
此问题不重复。
试试这个:
template <typename T, typename = void> struct has_operator {
enum { value = 0 };
};
// thanks super for great suggestion!
template <typename T> struct has_operator<T, std::void_t<decltype(std::declval<T>()())>> {
enum { value = 1 };
};
template<class T, typename = std::enable_if<has_operator<T>::value>> struct Caller: T
{
using T::operator();
};
这根据 SFINAE 的原则工作 - 模板实例化中的一些错误而不是整个编译失败只会使编译器忽略给定的实例化。所以首先我们用value = 0
定义has_operator
,也就是我们的"default value"。然后我们对类型 T 的模板进行特化。现在我们希望仅当 T::operator()
存在时才选择此特化。所以我们添加第二个模板参数并将其默认值设置为 decltype(&T::operator())
和 value = 1
。我们在这里不关心真实类型,我们关心的是如果 T::operator()
存在,这将编译得很好。并且编译器将 select 此专业化为此 T
。当它不存在时 - 编译器将 忽略 这个特化和 select "default" has_operator
,它有 value = 0
.
所以现在我们有 struct has_operator
,它 - 当像这样使用时:has_operator<T>::value
将产生常量值 0,当 T 没有 operator ()
时(注意任何参数你)和价值1,当有。您可以将它与 std::enable_if
一起使用(顺便说一下,它的工作方式几乎相同)。
可以使用此技术应用的事物列表相当长 - 几乎任何可以使编译成败的东西都可以使用。
不,没有办法做到这一点。
所有解决方案都需要知道调用的签名(准确的或兼容的),或者不依赖于重载。
事实上,即使您具有已知的签名,也无法可靠地检测到任何重载或模板调用运算符,因为隐式转换为函数指针允许欺骗 declval 测试。
您将不得不另辟蹊径解决您的问题,或者等待反思。
我需要一个类型特征 HasCall 来检查 T 的以下类型实例化的有效性:
template<class T> struct Caller: T
{
using T::operator();
};
有没有办法在 C++14 中做到这一点? 这是我的尝试,但它不起作用: https://godbolt.org/z/vxgJCR
编辑
我知道 SFINAE 及其运作方式。这个问题比仅仅检查某些表达式的有效性更困难。 我希望这些断言通过:
struct A {void operator()(int) {}};
static_assert(HasCall<A>, "Check must work with any set of arguments.");
struct B {void operator()() {}};
static_assert(HasCall<B>, "Check must work with any set of arguments.");
struct C {template<typename... Args> void operator()(Args&&...) {}};
static_assert(HasCall<C>, "Templated operators must be detected correctly.");
struct D {};
static_assert(!HasCall<D>, "No operator() at all.");
static_assert(!HasCall<void(*)()>, "Class cannot inherit from function pointers.");
检查表达式 &T::operator() 的有效性是不够的,因为它不适用于重载或模板 operator()。
请使用这些断言检查您的解决方案。
此问题不重复。
试试这个:
template <typename T, typename = void> struct has_operator {
enum { value = 0 };
};
// thanks super for great suggestion!
template <typename T> struct has_operator<T, std::void_t<decltype(std::declval<T>()())>> {
enum { value = 1 };
};
template<class T, typename = std::enable_if<has_operator<T>::value>> struct Caller: T
{
using T::operator();
};
这根据 SFINAE 的原则工作 - 模板实例化中的一些错误而不是整个编译失败只会使编译器忽略给定的实例化。所以首先我们用value = 0
定义has_operator
,也就是我们的"default value"。然后我们对类型 T 的模板进行特化。现在我们希望仅当 T::operator()
存在时才选择此特化。所以我们添加第二个模板参数并将其默认值设置为 decltype(&T::operator())
和 value = 1
。我们在这里不关心真实类型,我们关心的是如果 T::operator()
存在,这将编译得很好。并且编译器将 select 此专业化为此 T
。当它不存在时 - 编译器将 忽略 这个特化和 select "default" has_operator
,它有 value = 0
.
所以现在我们有 struct has_operator
,它 - 当像这样使用时:has_operator<T>::value
将产生常量值 0,当 T 没有 operator ()
时(注意任何参数你)和价值1,当有。您可以将它与 std::enable_if
一起使用(顺便说一下,它的工作方式几乎相同)。
可以使用此技术应用的事物列表相当长 - 几乎任何可以使编译成败的东西都可以使用。
不,没有办法做到这一点。
所有解决方案都需要知道调用的签名(准确的或兼容的),或者不依赖于重载。
事实上,即使您具有已知的签名,也无法可靠地检测到任何重载或模板调用运算符,因为隐式转换为函数指针允许欺骗 declval 测试。
您将不得不另辟蹊径解决您的问题,或者等待反思。