Неожиданный сбой SFINAE при использовании std :: result_of

В c ++ 14 предполагается, что std :: result_of приведет к SFINAE, если выражение некорректно сформировано *. Вместо этого я получаю ошибку компиляции («недопустимые операнды в двоичном выражении») в моем последнем случае ниже (то есть, позволяя компилятору выводить тип для std :: plus<>). Первые три случая работают как положено. Код и результаты показаны ниже.

#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/apply.hpp>
#include <iostream>
#include <utility>
#include <stdexcept>
#include <functional>

namespace mpl = boost::mpl;template <typename OP, typename T, typename OP_T = typename mpl::apply<OP, T>::type>
struct apply_if_ok: OP_T {

template <typename...Args, typename R = std::result_of_t<OP_T(Args...)>>
R operator()(Args&&...args) const {
return static_cast<OP_T>(*this)(std::forward<Args>(args)...);
}
template <typename...Args>
auto operator()(...) const {
// throw std::runtime_error("Invalid arguments");
return "Invalid arguments";
}
};int main() {
using OP = std::plus<mpl::_>;
int i = 3;

auto n1 = apply_if_ok<OP, void>()(1, 2);
std::cout << "plus (1, 2) = " << n1 << std::endl;

auto n2 = apply_if_ok<OP, void>()(1, &i);
std::cout << "plus (1, *) = " << n2 << std::endl;

auto n3 = apply_if_ok<OP, int>()(&i, &i);
std::cout << "plus (*, *) = " << n3 << std::endl;

// auto n4 = apply_if_ok<OP, void>()(&i, &i);
// std::cout << "plus (*, *) = " << n4 << std::endl;
}

Выход:

% c++ -std=c++1y -g -pedantic    sfinae_result_of.cc   -o sfinae_result_of
./sfinae_result_of
plus (1, 2) = 3
plus (1, *) = 0x7fff5e782a80
plus (*, *) = Invalid arguments

% c++ -v
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix

Любые указатели на то, что я делаю неправильно, будут оценены!

Благодарю.

  • От cppreference.com. Я думаю, что соответствующая стандартная ссылка — 20.10.7.6, комментарии к последней записи в таблице.

2

Решение

Это вызвано ошибка в libc ++, о котором я на самом деле только что сообщил несколько дней назад. (Обновить: Баг был исправлен в багажнике.)

Проблема в том, что их реализация «алмазного функтора» не соответствует требованиям. Например, они реализовали std::plus<void>::operator() следующее:

template <class _T1, class _T2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
auto operator()(_T1&& __t, _T2&& __u) const
{ return _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u); }

когда это должно быть

template <class _T1, class _T2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
auto operator()(_T1&& __t, _T2&& __u) const
-> decltype(_VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u))
{ return _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u); }

Пропажа задний обратный тип означает две вещи:

  1. Они больше не «идеально возвращаются»; вместо этого тип возвращаемого значения выводится с использованием правил для autoпо существу, вызывая его разложение. Конечный тип возвращаемого значения, когда выражение в нем правильно сформировано, эквивалентно возвращаемому decltype(auto),
  2. SFINAE больше не относится к выражению _VSTD::forward<_T1>(__t) + _VSTD::forward<_T2>(__u), В реализации без ошибок, operator() объявление будет удалено из набора перегрузки, разрешение перегрузки не будет выполнено, и std::result_of тогда будет делать свою дружелюбную к СФИНА магию. Вместо этого объявление функции успешно создается, выбирается с помощью разрешения перегрузки, а затем возникает серьезная ошибка, когда компилятор пытается создать экземпляр тела для фактического вывода возвращаемого типа.

Ваша проблема вызвана № 2.

9

Другие решения


По вопросам рекламы [email protected]