Подтвердить что ты не робот

Как проверить во время компиляции, что выражение является незаконным?

У меня проблема в моем приложении, где я хотел бы утверждать, что приложение-функция будет отклонено компилятором. Есть ли способ проверить это с помощью SFINAE?

Например, предположим, что я хотел бы подтвердить, что диапазон std::transform в const является незаконным. Вот что я до сих пор:

#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
4b9b3361

Ответ 1

Ваш вопрос похож на SFINAE + sizeof = определить, компилируется ли выражение.

Резюме этого ответа: sizeof оценивает тип переданного им выражения, включая создание экземпляра шаблона функции, но не вызывает вызов функции. Вот почему Lol4t0 наблюдает, что sizeof(std::transform(iter1(), iter1(), iter2(), func())) компилируется, даже если std::transform(iter1(), iter1(), iter2(), func()) не работает.

Ваша конкретная проблема может быть решена путем оценки шаблона из ответа Lol4t0 для любого выходного диапазона, который должен быть отправлен на std::transform. Однако общая проблема проверки в шаблоне, который компилируется вызов функции, представляется невозможной с помощью трюка sizeof + SFINAE. (для этого потребуется выражение времени компиляции, которое выводится из вызова функции времени выполнения).

Возможно, вы захотите попробовать ConceptGCC, чтобы убедиться, что это позволяет вам более точно выразить требуемую проверку времени компиляции.

Ответ 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& const, то есть константной ссылке на int, а не const int&, которая ссылается на константу int и сначала не имеют никакого смысла.

Хорошо, но мы можем определить, будет ли итератор постоянным с struct follwing:

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) };

};