【问题标题】:How to check at compile time that an expression is illegal?如何在编译时检查表达式是否非法?
【发布时间】:2012-05-14 12:40:08
【问题描述】:

我的应用程序中有一个问题,我想断言一个函数应用程序将被编译器拒绝。有没有办法通过 SFINAE 进行检查?

例如,假设我想验证 std::transformconst 的范围是非法的。这是我目前所拥有的:

#include <algorithm>
#include <functional>
#include <iostream>

namespace ns
{

using std::transform;

template<typename Iterator1, typename Iterator2, typename UnaryFunction>
  struct valid_transform
{
  static Iterator1 first1, last1;
  static Iterator2 first2;
  static UnaryFunction f;

  typedef Iterator2                   yes_type;
  typedef struct {yes_type array[2];} no_type;

  static no_type transform(...);

  static bool const value = sizeof(transform(first1, last1, first2, f)) == sizeof(yes_type);
};

}

int main()
{
  typedef int *iter1;
  typedef const int *iter2;
  typedef std::negate<int> func;

  std::cout << "valid transform compiles: " << ns::valid_transform<iter1,iter1,func>::value << std::endl;

  std::cout << "invalid transform compiles: " << ns::valid_transform<iter1,iter2,func>::value << std::endl;

  return 0;
}

不幸的是,我的特质拒绝合法和非法的情况。结果:

$ g++ valid_transform.cpp 
$ ./a.out 
valid transform compiles: 0
invalid transform compiles: 0

【问题讨论】:

  • constexpr 可能会有所帮助,只是快速思考一下。
  • 另一个问题是std::cout &lt;&lt; sizeof(std::transform(iter1(), iter1(), iter2(), func()));可以编译,而std::cout &lt;&lt; std::transform(iter1(), iter1(), iter2(), func());没有。
  • @Lol4t0 那是因为sizeof() 在编译期间不会评估它的参数。

标签: c++ sfinae typetraits c++-concepts


【解决方案1】:

您的问题类似于SFINAE + sizeof = detect if expression compiles

该答案的

摘要sizeof 评估传递给它的表达式的类型,包括实例化函数模板,但它不会生成函数调用。这就是 Lol4t0 观察到 sizeof(std::transform(iter1(), iter1(), iter2(), func())) 编译即使 std::transform(iter1(), iter1(), iter2(), func()) 不编译的原因。

您的具体问题可以通过评估 Lol4t0 的答案中的模板来解决要提供给std::transform 的任何输出范围。但是,使用sizeof + SFINAE 技巧似乎无法解决在模板中验证函数调用是否会编译的一般问题。 (它需要一个可从运行时函数调用派生的编译时表达式)。

您可能想尝试ConceptGCC 看看这是否允许您以更方便的方式表达必要的编译时检查。

【讨论】:

  • 您的OutputIterator 类型可以与InputIterator 类型完全不同,这取决于Operator 返回类型
  • @Lol4t0 只看OutIt能否转成InIt。
  • 你不明白这一点:OutputIterator 类型可以与 InputIterator 类型完全不同,但是 std:transform 仍然可以工作(并且你的验证将失败) . Example.
  • 另请注意,std::is_const&lt;Iterator&gt;; std::is_const&lt;Iterator::value_type&gt;; std::is_const&lt;Iterator::reference&gt;; 也不起作用:(
  • @rhalbersma:感谢您的回答,但我真正想验证的是,std::transform实现 是否符合其规范,而不是特定参数是否符合 @987654337 @。从你的解释看来,我可能做不到。
【解决方案2】:

在我的回答中,我想关注问题,如果给定迭代器常量,如何确定: 提到了std::is_const,但在这种情况下它对我不起作用(gcc 4.7)。

我假设,它是像这样实现的

template <typename T>
struct is_const
{
    enum {value = false };
};

template <typename T>
struct is_const<const T>
{
    enum {value = true };

};

现在,无法使用此结构检查引用类型,它们不会匹配特化,因为 const T 将匹配 int&amp; const,即 对 int 的常量引用,而不是 const int&amp;,即是对常量int的引用,首先没有任何意义。

好的,但是我们可以确定迭代器是否与以下结构保持一致:

template <typename Iterator>
struct is_iterator_constant
{
    typedef char yes_type;
    typedef struct{ char _[2];}  no_type;
    template <typename T>
    static no_type test(T&);

    template <typename T>
    static yes_type test(...);

    enum {value = sizeof(test<typename std::iterator_traits<Iterator>::value_type>(*Iterator())) == sizeof(yes_type) };

};

【讨论】:

猜你喜欢
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多