编译时检查输出(<<)和关系(<、>等)是否可用

Compile-time check whether output (<<) and relational (<, >, etc.) are available

本文关键字:lt gt 是否 关系 检查 编译 输出      更新时间:2023-10-16

我目前正在使用is_call_possible第三方代码

https://github.com/jaredhoberock/is_call_possible

以在编译时确定成员是否可用。这个例子效果很好:

#include <string>
#include "is_call_possible.h"
DEFINE_IS_CALL_POSSIBLE(is_call_possible, operator())
DEFINE_IS_CALL_POSSIBLE(test_available, test)
struct Foo {
  void operator()(double) {}
  double test(std::string) { return 0; }
};
int main(int argc, const char * argv[]) {
  static_assert(is_call_possible<Foo, void(double)>::value,"err"); //success
  static_assert(test_available<Foo, double(std::string)>::value,"err"); //success
  return 0;
}

但这对普通的非成员不起作用,所以我不能对输出和关系运算符做同样的操作:

DEFINE_IS_CALL_POSSIBLE(output_available, operator<<) //error
DEFINE_IS_CALL_POSSIBLE(less_available, operator<) //error
DEFINE_IS_CALL_POSSIBLE(greater_available, operator>) //error

你能给我指一下方便的第三方代码(或你自己的代码)吗?

如果更容易的话,底层解决方案("第三方代码")可以在C++11中实现,但我想我不会注意到我自己的代码中的差异(作为第三方码的用户)。

假设C++11是一个选项,decltype编译时构造可以与SFINAE一起使用,基本上对类型进行"概念检查"(尽管C++11标准中缺乏真正的概念检查),看看它们是否支持操作。

(未经测试,因为我目前缺少C++11编译器[诅咒你的Windows~!],但我相信如果我的错误存在,会有人发现的)。

Ex。

template<typename T> struct voidify{typedef void type;};
template<typename T, typename U, typename enable=void>
struct has_operator_less {
  enum{value=false};
};
template<typename T, typename U>
struct has_operator_less<T, U, typename voidify<decltype(
  std::declval<T>() < std::declval<U>() // <-- this is the 'concept' check
)>::type> {
  enum{value=true};
};

您可以使用std::enable_if构造来启用/禁用任何依赖于这两种类型的operator<存在与否的函数:

template<typename T, typename U>
typename std::enable_if<
  has_operator_less<T, U>::value, I_am_the_result_type_of_the_function
>::type
I_depend_on_the_existence_of_the_less_than_operator(const T& a, const U& b) {...}

如果您想要为缺少operator<的类型提供该函数的替代实现,只需使用否定即可启用:

template<typename T, typename U>
typename std::enable_if<
  !has_operator_less<T, U>::value, I_am_the_result_type_of_the_function
  // ^ note the negation
>::type
I_depend_on_the_existence_of_the_less_than_operator(const T& a, const U& b) {...}

因此,现在您有了在编译时为具有和不具有这些运算符的类型确定的实现,并且可以对任何其他运算符或函数名或任何您想要的重复此解决方案。只需将您正在检查的概念放在decltype中即可。

所有这些都不需要在构建之前有一个单独的配置步骤。

(同样,未经测试的代码-.-',但肯定是正确的;其他人都知道编辑按钮在哪里:-p)

提升型特征可以做到这一点。

注意:模板代码仍然存在问题(无论您使用哪种方法来检测它)。例如,vector<T>::operator<假设T有一个operator<,因此您得到以下内容:

struct Silly {};
std::cout << boost::has_less<Silly>::value << std::endl;  // 0
std::cout << boost::has_less<std::vector<Silly>>::value << std::endl;  // 1