3

Say i got template function like this

template <typename T> bool func(T a)
{
  if(a.X())
    return a.Y();
  return false;
}

Now every class i use as parameter to this function has function X(), but not every class i use as parameter has function Y(). However if function a.X() returns true then i have guaranteed that given class has function Y(). Can i make this code compile somehow since i know that function Y() which compiler is whining about missing on certain types will never be called? This function is in reality really big and types used are many so making a number of specializations is impractical.

roalz
  • 2,699
  • 3
  • 25
  • 42
user1316208
  • 667
  • 1
  • 5
  • 12
  • This will only work if `T::X()` can be evaluated at compile time and `a` is known at compile time, but some template bla bla is involved. Please clarify whether this is the case! If this is not the case, then you can't detect cases at compile time, where `T::X()` returns true, but `T::Y()` does not exist. You can, however, enforce this at run-time. – Markus Mayr Jul 08 '14 at 09:42
  • 1
    `if (a) return b; return false;` is a complex way of writing `return a and b;`. – Konrad Rudolph Jul 08 '14 at 09:58

2 Answers2

3

SFINAE may help, something like: (https://ideone.com/XmjQY8)

#include <type_traits>
#include <cstdint>

#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               \
    template <typename U>                                                   \
    class traitsName                                                        \
    {                                                                       \
    private:                                                                \
        template<typename T, T> struct helper;                              \
        template<typename T>                                                \
        static std::uint8_t check(helper<signature, &funcName>*);           \
        template<typename T> static std::uint16_t check(...);               \
    public:                                                                 \
        static                                                              \
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
    }

DEFINE_HAS_SIGNATURE(has_X, T::X, bool (T::*)());
DEFINE_HAS_SIGNATURE(has_Y, T::Y, bool (T::*)());

template <typename T>
typename std::enable_if<has_X<T>::value && has_Y<T>::value, bool>::type
func(T a)
{
  if(a.X())
    return a.Y();
  return false;
}

template <typename T>
typename std::enable_if<!has_X<T>::value || !has_Y<T>::value, bool>::type
func(T /*a*/)
{
    return false;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • OK this looks like the answer - i dont know what type_traits is and what exactly is happening there but i will study it – user1316208 Jul 08 '14 at 09:58
2

Here is another version inspired by this answer which is a little shorter (and nicer in my opinion :) ).

struct Action
{
    template <typename T>
    static bool func_real(T a){return func(a, special_());}

private:

    struct general_ {};
    struct special_ : general_ {};
    template<typename> struct bool_ { typedef bool type; };

    template<typename S, typename bool_<decltype(std::declval<S>().Y())>::type = 0>
    static bool func(S a, special_) {
        cout<<"Y() exists"<<endl;
        if(a.X()){
            return a.Y();
        }
        return false;
    }

    template<typename S>
    static bool func(S a, general_) {
        cout<<"Y() does not exist"<<endl;
        return false;
    }
};

Here is a live demo.

Community
  • 1
  • 1
Scis
  • 2,934
  • 3
  • 23
  • 37
  • Nice solution. Was trying to figure out something similar, but did not succeed. Can you explain to me why the "= 0" in the template parameter works? – JohnB Jul 08 '14 at 10:49
  • @JohnB: `0` is `false`. – Jarod42 Jul 08 '14 at 11:02
  • @JohnB it's in order to give this argument a default value so in case there's a proper `Y` the argument will be initialized without the need to specify it explicitly (you can place `true` or `42` as well :) ). – Scis Jul 08 '14 at 11:10
  • Thank you. I got confused because the left-hand side of the = describes a type, and 0 is a value. Obviously, the compiler does not care? – JohnB Jul 08 '14 at 13:49
  • Btw, I think you do not need the `bool_` magic. `template().Y()) = 0>` works as well. – JohnB Jul 08 '14 at 13:58