Черты типа, чтобы определить, есть ли у вызываемого объекта побочные эффекты?

Мой вопрос прост задать, но я думаю, трудно ответить.

В С++ 14 есть ли способ проверить, имеет ли вызываемый объект (функция, член функции, лямбда-функция, std::function и т. д.) побочный эффект или нет?

Если да, то как бы черты типа:

template <class T>
struct has_side_effects;

будет, как?

Меня устраивает трейт, который возвращает ложноположительный результат (говорит, что у функции есть побочные эффекты, а на самом деле их нет), но не приемлю трейт, который возвращает ложноотрицательный результат (говорит, что функция не имеет побочных эффектов, а она есть).

Например, мне нужна черта:

auto comparator = [](const auto& x, const auto& y){return y > x;};
bool result = std::has_side_effects<decltype(comparator)>::value;

вернуть false.


person Vincent    schedule 25.01.2016    source источник
comment
Это невозможно, если функция не является constexpr   -  person    schedule 25.01.2016
comment
статический анализатор может помочь... но это кажется нетривиальной задачей.   -  person Jarod42    schedule 25.01.2016
comment
@DieterLücking это невозможно и для constexpr, если только это не гарантируется разработчиком. constexpr функции могут иметь ответвления, приводящие к побочным эффектам.   -  person 101010    schedule 25.01.2016
comment
Кажется, это может свести к проблеме остановки, не так ли?   -  person erip    schedule 25.01.2016
comment
@erip: Это сведется к проблеме остановки только в том случае, если не будут допущены ложные срабатывания. В противном случае, как заявил Yakk, существует тривиальный алгоритм, который просто говорит, что все имеет побочные эффекты :-)   -  person Dirk Herrmann    schedule 25.01.2016


Ответы (1)


Как уже говорилось, template<class T> using has_side_effects = std::true_type; решает большую часть вашей проблемы. Просто скажите, что все имеет побочные эффекты, и отправьте это. Ложноположительные, но не ложноотрицательные!

В общем случае нетривиальные свойства алгоритма, закодированного в полной по Тьюрингу системе, не могут быть вычислены. Это эквивалентно проблеме остановки. Так что проблема не может быть решена в целом.

В особых случаях C++ практически не предлагает отражения содержимого алгоритма. В лучшем случае он дает некоторое представление об интерфейсе алгоритма, но интерфейс алгоритма/функции не содержит информации о чистоте алгоритма.

Самое близкое, что вы можете получить, это «может ли он быть вызван в контексте constexpr».

В конкретном случае:

auto comparator = [](const auto& x, const auto& y){return y > x;};
bool result = std::has_side_effects<decltype(comparator)>::value;

результат должен быть true, как:

struct evil {
  static int count() { static int r = 0; return ++r; }
  friend bool operator<( evil lhs, evil rhs ) { count(); return false; }
};

то comparator(evil{}, evil{}) имеет побочный эффект. Возвращать false при передаче comparator просто неправильно.

person Yakk - Adam Nevraumont    schedule 25.01.2016
comment
В общем случае нетривиальные свойства алгоритма, закодированного в полной по Тьюрингу системе, не могут быть вычислены. Для тех, кому интересно, это теорема Райса. - person erip; 25.01.2016
comment
@erip, чтобы быть справедливым. Теорема Райса касается языка, принятого машиной Тьюринга. На самом деле вы можете иметь дело с нетривиальными свойствами самого вычисления (скажем, будет ли оно принято менее чем за миллион шагов?). Требуется некоторое время, чтобы перевести побочные эффекты в свойство приемлемого языка: вы перекодируете свою абстрактную машину для записи X на ленте, когда она дает побочный эффект, затем язык, который принимает строку со списком X, если и только если переданная строка исходный алгоритм выводит столько X. - person Yakk - Adam Nevraumont; 25.01.2016
comment
Это действительно так. Я пытался придумать какие-то сокращения, и это было сложно. - person erip; 25.01.2016