jeudi 6 juillet 2023

Using std::enable_if with complex predicates

Having to use C++14 I'd like to use std::enable_if to make a function only being available given certain constraints. I do so using or_<> taken from the libc header type_traits instead of std::disjunction (no C++17 available in my environment) in order to move the constraint logic into a separate construct.

However, I seem to be missing something, because I can't manage to get it to compile.

My code:

#include <type_traits>
#include <iostream>
#include <vector>
#include <list>

template <typename T>
struct IsVector : public std::false_type {};

template <typename T>
struct IsVector<std::vector<T>> : public std::true_type {};

template <typename T>
struct IsList : public std::false_type {};

template <typename T>
struct IsList<std::list<T>> : public std::true_type {};

// taken from libc type_traits
template <bool, typename, typename>
struct conditional;

template <typename...>
struct or_;

template <>
struct or_<> : public std::false_type {};

template <typename _B1>
struct or_<_B1> : public _B1 {};

template <typename _B1, typename _B2>
struct or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type {};

template <typename _B1, typename _B2, typename _B3, typename... _Bn>
struct or_<_B1, _B2, _B3, _Bn...> : public conditional<_B1::value, _B1, or_<_B2, _B3, _Bn...>>::type {};
// ---

template <typename T>
struct IsVectorOrList : public or_<IsVector<T>, IsList<T>>::type {};

template <typename T>
typename std::enable_if<IsVector<T>::value || IsList<T>::value, void>::type
// replacing with this line does not work
//typename std::enable_if<IsVectorOrList<T>::value, void>::type
foo(const T& list)
{
    for (const auto& item : list)
    {
        std::cout << item << std::endl;
    }
}


int main()
{
    foo(std::vector<int>{17, 42});
    foo(std::list<float>{1.0, 2.71, 3.14});
}

When using typename std::enable_if<IsVector<T>::value || IsList<T>::value, void>::type as constraint it works fine. If I use typename std::enable_if<IsVectorOrList<T>::value>::type the compiler complains:

traits.cpp:32:8: error: invalid use of incomplete type ‘struct conditional<true, IsVector<std::vector<int> >, IsList<std::vector<int> > >’
   32 | struct or_<_B1, _B2> : public conditional<_B1::value, _B1, _B2>::type {};
      |        ^~~~~~~~~~~~~
traits.cpp:20:8: note: declaration of ‘struct conditional<true, IsVector<std::vector<int> >, IsList<std::vector<int> > >’
   20 | struct conditional;
      |        ^~~~~~~~~~~

How do I make it work?

Aucun commentaire:

Enregistrer un commentaire