Issue
I've been using code similar to the following in MSVC projects for the last year or so, and ran into an issue trying to use it with 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;
}
GCC gives the error error: 'get' was not declared in this scope; did you mean 'std::get'?
Clang gives the error error: use of undeclared identifier 'get'
icc and MSVC both compile properly.
I'm wondering if this has something to do with GLM's implementation, because I've never had issues with custom structured bindings with GCC in the past.
I was wondering if anyone knows what is going on here. Are icc and MSVC behaving incorrectly by accepting the code, or are Clang and GCC behaving incorrectly by rejecting the code?
Here's an example of the four different compilers handling this on Compiler Explorer: https://godbolt.org/z/6PCWyn
Solution
I believe GCC & Clang are correct.
Here's what cppreference says about structured bindings:
The expression
std::tuple_size<E>::value
must be a well-formed integer constant expression, ...For each identifier, a variable whose type is "reference to
std::tuple_element<i, E>::type
" is introduced ... The initializer for the i-th variable is
e.get<i>()
, if lookup for the identifierget
in the scope ofE
by class member access lookup finds at least one declaration that is a function template whose first template parameter is a non-type parameter- Otherwise,
get<i>(e)
, whereget
is looked up by argument-dependent lookup only, ignoring non-ADL lookup.
(emphasis mine)
You have to move your get()
overloads to the namespace glm
.
Answered By - HolyBlackCat Answer Checked By - Pedro (WPSolving Volunteer)