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

Void_t не работает на Visual Studio 2015

Я не понимаю, почему следующий тест всегда терпит неудачу с Visual Studio 2015 (триггеры static_assert):

#include <type_traits>
using namespace std;

template<class T> using try_assign = decltype(declval<T&>() = declval<T const&>());
template<class, class = void> struct my_is_copy_assignable : false_type {};
template<class T> struct my_is_copy_assignable<T, void_t<try_assign<T>>> : true_type {};

int main()
{
    static_assert(my_is_copy_assignable<int>::value, "fail");
    return 0;
}

Это в основном транскрипция примера использования Уолтера E Брауна void_t из его презентации cppcon 2014 "Современное метапрограммирование шаблона - сборник".

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

template<class T>
using try_assign = decltype(declval<T&>() = declval<T const&>());

template<class T>
struct my_is_copy_assignable
{
  template<class Q, class = try_assign<Q>>
  static true_type tester(Q&&);
  static false_type tester(...);
  using type = decltype(tester(declval<T>()));
};

Я знаю о std::is_copy_assignable, но мне просто интересно понять различные методы метапрограммирования, доступные в разных версиях С++. Я прочитал несколько потоков о void_t в Интернете, но я до сих пор не понимаю, почему этот пример терпит неудачу.

Интересно, что с GCC 4.8.2 он отлично работает (с использованием обходного решения CWG 1558, которое совпадает с версией Microsoft).

Является ли это известной ошибкой Visual Studio, или я делаю что-то неправильно?

4b9b3361

Ответ 1

Это похоже на проблему SFINAE в VС++. Использование зависимого decltype в аргументе шаблона частичной специализации шаблона класса пока не поддерживается. Он должен работать в обновлении версии VS 2015.

Ответ 2

Уолтер Э. Браун на CppCon 2014 также упомянул следующую факторизацию, которая позволяет заменить try_assign на произвольное условие.

#include <type_traits>
#include <utility>

template<class T>
using try_assign = decltype(std::declval<T&>() = std::declval <T const &>());

template<class T, template<class> class Op, class = void>
struct is_valid : std::false_type { };

template<class T, template<class> class Op>
struct is_valid<T, Op, std::void_t<Op<T>>> : std::true_type { };

template<class T>
using is_copy_assignable = is_valid<T, try_assign>;

int main()
{
    static_assert(is_copy_assignable<int>::value, "fail");
    return 0;
}

Эта факторизация компилирует ОК с VS 2015. Теперь удалите is_copy_assignable и замените на is_valid. Вы получаете код, который вы представили и который не компилируется (VS 2015).

Это говорит о наличии ошибки в VS 2015, и она не связана с CWG 1558. В выпуске CWG стандарт неясно, могут ли неиспользуемые аргументы в специализированных шаблонах псевдонимов привести к ошибке замены или просто игнорируются.