编译时检查输出(<<<<<<<<<<<<<<<">等)

时间:2013-06-21 20:03:47

标签: c++ c++11

我目前正在使用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中实现,如果它更容易,但我想我不会注意到我自己的代码(作为第三方代码的用户)的差异

2 个答案:

答案 0 :(得分:1)

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

(未经测试,因为我现在缺少一个C ++ 11编译器[诅咒你的Windows~!],但我确信有人会抓住我的错误)。

实施例

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)

答案 1 :(得分:0)

Boost Type Traits会这样做。

注意:模板代码仍然存在问题(无论您使用哪种方法来检测它)。例如,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