I want to write a generic accessor for a class member regardless whether it is a function or or a data member:
#include <type_traits>
namespace traits
{
    template <typename T, typename = void>
    struct _name;
    template <typename T>
    struct _name<T, std::void_t<decltype(std::declval<T>().name)>>
    {
        constexpr decltype(auto) operator()(const T &t) const
        {
            return t.name;
        }
    };
    template <typename T>
    struct _name<T, std::void_t<decltype(std::declval<T>().name())>>
    {
        constexpr decltype(auto) operator()(const T &t) const
        {
            return t.name();
        }
    };
    template <typename T>
    decltype(auto) name(const T &t)
    {
        return _name<T>{}(t);
    }
}
#include <string>
struct beb
{
   std::string name = "beb";
};
struct bob
{
   std::string name() const
   {
       return "bob";
   }
};
#include <iostream>
int main()
{
    std::cout << traits::name(bob());
    std::cout << traits::name(beb());
}
I am using SFINAE with void_t specialization, but it works with only single specialization. Otherwise it gives an error saying error C2953: 'traits::_name<T,void>': class template has already been defined.
MSVC latest: https://godbolt.org/z/h9WT58z8P - does not compile
GCC 12.2: https://godbolt.org/z/vc3K1M7x5 - compiles
Clang 15.0.0: https://godbolt.org/z/dqGEMfYWK - does not compile
- Should this code compile? (It compiles only for GCC)
 - How to make it compilable?
 
_name is a customization point within a traits namespace. By default it accesses name using name or name(). But one can provide a specialization to use, for example getName().