Почему я могу создать пользовательские структурированные привязки для glm :: ve c в MSV C и i cc, но не в Clang и G CC? - PullRequest
1 голос
/ 21 марта 2020

Я использовал код, подобный следующему, в проектах MSV C за последний год или около того, и столкнулся с проблемой, пытаясь использовать его с g ++.

#include <utility>
#include <glm/glm.hpp>

namespace std {
  template< std::size_t I, auto N, class T, auto Q>
  constexpr auto& get(glm::vec<N, T, Q>& v) noexcept { return v[I]; }

  template< std::size_t I, auto N, class T, auto Q>
  constexpr const auto& get(const glm::vec<N, T, Q>& v) noexcept { return v[I]; }

  template< std::size_t I, auto N, class T, auto Q>
  constexpr auto&& get(glm::vec<N, T, Q>&& v) noexcept { return std::move(v[I]); }

  template< std::size_t I, auto N, class T, auto Q>
  constexpr const auto&& get(const glm::vec<N, T, Q>&& v) noexcept { return std::move(v[I]); }

  template <auto N, class T, auto Q>
  struct tuple_size<glm::vec<N, T, Q>> : std::integral_constant<std::size_t, N> { };

  template <std::size_t I, auto N, class T, auto Q>
  struct tuple_element<I, glm::vec<N, T, Q>> {
    using type = decltype(get<I>(declval<glm::vec<N,T,Q>>()));
  };
}// end std


auto f(){
  auto [x,y,z] = glm::vec3(1);
  return x + y + z;
}

G CC выдает ошибку error: 'get' was not declared in this scope; did you mean 'std::get'?
Clang выдает ошибку error: use of undeclared identifier 'get'
i cc и MSV C оба компилируются правильно.

Мне интересно, связано ли это с реализацией GLM, потому что у меня никогда не было проблем с пользовательскими структурированными привязками с G CC.

Мне было интересно если кто-нибудь знает, что здесь происходит. I cc и MSV C ведут себя некорректно, принимая код, или Clang и G CC ведут себя некорректно, отклоняя код?

Вот пример четырех различных компиляторов, обрабатывающих это на компиляторе Исследователь: https://godbolt.org/z/6PCWyn

1 Ответ

3 голосов
/ 21 марта 2020

Я считаю, что G CC и Clang верны.

Вот что cppreference говорит о структурированных привязках:

Выражение std::tuple_size<E>::value должно быть правильно сформированное целочисленное константное выражение, ...

Для каждого идентификатора вводится переменная, тип которой "ссылка на std::tuple_element<i, E>::type" ... Инициализатор для i-й переменной -

  • e.get<i>(), если при поиске идентификатора get в области действия E при поиске доступа к членам класса будет найдено как минимум одно объявление, являющееся шаблоном функции, первый параметр шаблона которого является параметром нетипичного типа
  • В противном случае get<i>(e), , где get ищется только в зависимости от аргумента, игнорируя поиск без ADL .

(выделено мной)

Вы должны переместить свои get() перегрузки на namespace glm.

...