Has_f<T> not working

I am trying to get a a type predicate Has_f<T> to work. It's purpose is to check if a type T has a member named f. I am interested in using the specific algorithm shown below.

With this objective in mind, I have written the following type function get_Tf_result<T> which is intended to return the type of member T::f (if it exists).

The template contains an overloaded function check().

The first overload returns the type of U::f (if it exists). If it doesn't exist, this overload will be eliminated by SFINAE and the second overload will return type "substitution_failure" (a dummy type that indicates that the type U doesn't contain member f()):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<typename T>
struct get_Tf_result
{
private:
   /// can call U::f()
   template<typename U = T>
   static auto check() -> decltype(U::f())
   {
   }

   /// can't call U::f()
   static substitution_failure check(...)
   {
   }

public:
   using type = decltype( check(std::declval<T>()) );
};



I have tested it as follows:
a) A type A has a function f() that returns int.
b) A type B has no function f().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct A
{
   int f()
   {
      return 1;
   }
};


struct B
{
};


void test()
{
   typename get_Tf_result<A>::type j {};

   cout << "j is of typeid " << typeid(j).name() << endl;


   typename get_Tf_result<B>::type sf {};

   cout << "sf is of typeid " << typeid(sf).name() << endl;
}


get_Tf_result<A>::type should return int. However, it returns substitution_failure.
This means that this instantiation is unable to detect function A::f(), which is wrong.

Right now, I am considering only this algorithm, since it seems to be the simplest. It works for a function ::f() (ie, in the global namespace), but not for T::f().

What seems to be the problem here?

Thanks.
unable to detect function A::f(), which is wrong.

Why is it wrong? f is not a static member function, A::f() is invalid code (unless you're inside a member function of a class derived from A). To call a non-static member function, use the dot with an expression on the left, not :: with a type on the left..

Try with

1
2
3
4
   template<typename U = T>
   static auto check(U&&) -> decltype(std::declval<U>().f())
   {
   }


(unused parameter added because you are calling it with an argument - as written it wouldn't have worked even with a static member function)
Last edited on
cubbi/others: could you please recommend a (preferably self-contained) source to try and learn this bit of C++? I'm googling to random links and not getting the entire picture. many thanks
Chapters 2 (and may be 3) of 'Modern C++ Design: Generic Programming and Design Patterns Applied' by Alexandrescu. https://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315

Note: Pre-C++11; it was modern when it came out 16 years ago.
Cubbi is most likely right ... A.f() is non static. Therefore A needs to be instantiated first.

I am trying this out and will revert asap.

Thanks.
A::f() has no relation to B::f() as the two structs are themselves unrelated, so having the same name may not mean much but in any case you may be able to check it in the following way if you wish:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <string>

struct A
{
   int f()
   {
      return 1;
   }
};
struct B
{
};
struct C
{
    double f()const
    {
       return 3.14;
    }
};
struct D
{
    bool f()const
    {
        return (9%2 == 0);
    }
};

template<class T>
auto get_Tf_result(T* obj) -> decltype( obj->f())
{
    return     obj->f();
}
auto get_Tf_result(...) -> std::string
// ellipsis lowest conversion rank, so this overload chosen only if above template overload ignored
{
    return "f() not defined";
}
int main()
{
    A a{}; B b{}; C c{}; D d{};
    std::cout << get_Tf_result(&a) << "\n";
    std::cout << get_Tf_result(&b) << "\n";
    std::cout << get_Tf_result(&c) << "\n";
    std::cout << get_Tf_result(&d) << "\n";
}


Note that in this case the function signatures of f() are the same for each struct. If f() were to have different function signatures, you could use type_traits to check this as well in the following way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <type_traits>

struct A {int f(){return 1;}};
struct B {};
struct C {void f(const A& , const B& , bool )const {}};

template <typename T>
struct has_f { static bool const value = false; };

template <> struct has_f <A> {static bool const value = true;};
template <> struct has_f <C> {static bool const value = true;};

template <typename T>
void check_f(const T& )
{
    if(has_f<T>::value)
    {
        std::cout << "Has f() \n";
    }else { std::cout << "No f() \n";};
}

int main()
{
    A a{}; B b{}; C c{};
    check_f (a);
    check_f (b);
    check_f (c);
}
I have been trying both approaches, Cubbi's and gunner's.

First, gunner's approach:

He has used a function template get_Tf_result<>() rather than a class template get_Tf_result<>.

I have used this, (after modifying it to use a reference rather than a pointer:

1
2
3
4
5
6
7
8
9
10
11
12
13
template<typename T>
auto get_Tf_result(T& t) -> decltype(t.f())
{
    return t.f();
}

/** The ellipsis has the lowest conversion rank, 
    so this overload is chosen only if 
    the above template overload fails. */
substitution_failure get_Tf_result(...)
{
    return substitution_failure {};
}


It is tested below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// Test cases ...
struct A
{
   int f()
   {
      return 1;
   }
} a;

struct B
{
} b;

struct C
{
   double f()
   {
      return 1.1;
   }
} c;


void test()
{
   cout << "get_Tf_result(a) returns type: " 
        << typeid(get_Tf_result(a)).name() 
        << endl;

   cout << "get_Tf_result(b) returns type: " 
        << typeid(get_Tf_result(b)).name() 
        << endl;

   cout << "get_Tf_result(c) returns type: " 
        << typeid(get_Tf_result(c)).name() 
        << endl;
}


The function works correctly. It discriminates correctly between (1) types containing a function f (such as A and C), returning f()'s return type and (2) types that don't contain a function f (such as B), returning substitution_failure.

Unfortunately, the problem with this approach is that I can't plug this function template into the has_f<> function template which expects the get_Tf_result<> template to contain a member named type. Obviously a function template can't contain such a member.


Therefore, I tried Cubbi's approach. Unfortunately, it doesn't discriminate between types that do and don't contain a function f() and instead returns substitution_failure in both cases.

I tried to analyze this using the following code in C::B:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct failure
{
};

template<typename U>
static auto check() -> decltype(std::declval<U>().f())
{
}

static failure check(...)
{
    return failure {};
}

struct A
{
    int f()
    {
        return 1;
    }
};


int main()
{
    cout << typeid(check<A>()).name() << endl;

    return 0;
}


Perhaps the following compilation error throws some light:


error: static assertion failed: declval() must not be used!|


C::B displays the <type_traits> header with the following code highlighted:

1
2
3
4
5
6
7
8
  template<typename _Tp>
    inline typename add_rvalue_reference<_Tp>::type
    declval() noexcept
    {
      static_assert(__declval_protector<_Tp>::__stop,
		    "declval() must not be used!");
      return __declval_protector<_Tp>::__delegate();
    }


Any advice?

Cubbi had asked which book to refer for Metaprogramming. The original has_f<> example is taken from Stroustrup's "The C++ Prog Lang", 4th Ed, Ch 28 (Metaprogramming).

Thanks.
I can't plug this function template into the has_f<> function template

has_f<> is a template struct, not function template, with one member value, not type

Cubbi had asked which book to refer for Metaprogramming

the question was from me :)) but thanks
Last edited on
you can use std::enable_if to specialize, in turn, a template class for has_f types:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <type_traits>

struct A{};
struct B{};

template <typename T> struct has_f { static bool const value = false; };

template <> struct has_f <A> {static bool const value = true;};

template<class T, class Enable = void> // primary template
class F {public: void print()const {std::cout << "No f() \n";}};

template<class T> // specialization for has_f  types
class F <T, typename std::enable_if<has_f<T>::value>::type> {public: void print() const {std::cout << "Has f() \n";}};

int main()
{
   F <int> f1{}; f1.print();
   F <A> f2{}; f2.print();
   F <B> f3{}; f3.print();
}

SSteven wrote:
Any advice?

posting a complete program that demonstrates the problem would help.
My first comment applied to your original code fragments padded up to compile can be seen in action here: http://coliru.stacked-crooked.com/a/e94d456c58edfbba

I have the following constructs. Both are from Stroustrup's TC++PL4:
get_f_result<T> : yields the return type of a call of function f().
has_f() : determines if function f() exists.

I also have developed get_Tf_result<T>: yields the return type of a call of function t.f() where t is of type T and I had posted this in my first post.

I haven't yet developed has_Tf, since that's where I am stuck.

Therefore, I'm posting has_f() and get_f_result<T> and associated constructs, as requested by Cubbi. (These are all from TC++PL4). They work for ::f(), but not for t.f(). I'm trying to get a modification for t.f().

1) substitution_failure and substitution_succeeded which indicate failure and success respectively:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// Represents a failure to declare something
struct substitution_failure
{
};


/// Represents substitution success
template<typename T>		/// primary template
struct substitution_succeeded : std::true_type
{
};

/// Represents substitution failure
template<>				/// complete specialization
struct substitution_succeeded<substitution_failure> : 
			std::false_type
{
};



2) has_f and Has_f:

1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
struct has_f : 
    substitution_succeeded<typename get_f_result<T>::type>
{
};


template<typename T>
constexpr bool Has_f()
{
   return has_f<T>::value;
}



3) get_f_result<T> :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<typename T>
struct get_f_result
{
private:
   /// can call f(x)
   template<typename X>
   static auto check(X const& x) -> decltype(f(x))
   {
   }

   /// can't call f(x)
   static substitution_failure check(...)
   {
   }

public:
   using type = decltype( check(std::declval<T> ()) );
};
what is the difference envisaged b/w has_f() and has_Tf()?

get_f_result<T> : yields the return type of a call of function f().

could also use std::result_of, for e.g in here: http://www.cplusplus.com/forum/general/208795/#msg987780
1
2
3
4
   using print_type = std::result_of<decltype(&F<A>::print)(F<A>)>::type;
   static_assert(std::is_same<print_type, void>::value, "");//first option
 if(std::is_same<print_type, void>::value)std::cout << "Void \n";//second option
  //  print_type a{};//compile-time error : 'a' declared void 
Topic archived. No new replies allowed.