Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to detect the constness of a class' method using SFINAE?

Consider this struct:

struct foo {
  void dummy() const {}
};

Is it possible to detect the constness of this method using SFINAE?

For example, I would like to capture this property in a trait that could be usable in a static_assert:

static_assert(is_const_method<decltype(&foo::dummy)>::value, "Not const!");

I thought that either std::is_const or std::remove_const would help me here but they don't seem to encompass this "type" of constness.

Thanks,

like image 588
piwi Avatar asked Nov 29 '22 16:11

piwi


2 Answers

Sure, looks like this:

#include <type_traits>

template <class T>
struct is_const_method
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...)>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const>
    : std::true_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile>
    : std::true_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) &>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const &>
    : std::true_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile &>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile &>
    : std::true_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) &&>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const &&>
    : std::true_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) volatile &&>
    : std::false_type
{
};

template <class R, class C, class ...T>
struct is_const_method<R (C::*)(T...) const volatile &&>
    : std::true_type
{
};

struct foo {
  void dummy() const {}
};

int main()
{
    static_assert(is_const_method<decltype(&foo::dummy)>::value, "Not const!");
}
like image 137
Howard Hinnant Avatar answered Dec 01 '22 05:12

Howard Hinnant


You can just use partial specializations.

// false by default
template <typename Fun>
struct is_const_function : std::false_type {};

// breakdown member function type
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile> : std::true_type {};
// consider ref-qualified ones for compilers that support it
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const&&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile&> : std::true_type {};
template <typename Class, typename Result, typename... Args>
struct is_const_function<Result (Class::*)(Args...) const volatile&&> : std::true_type {};

You could also add more specializations to catter for C-style variadic functions, but frankly, my dear, I don't give a damn.

like image 25
R. Martinho Fernandes Avatar answered Dec 01 '22 05:12

R. Martinho Fernandes