Templates and overloading problem

  • Follow


Hi All,
I was wondering if someone can give me assistance with the following
small program.  There are two sections controlled by an #if.  The
first section compiles and runs correctly (using g++), the alternative
section errors out.  Both sections are attempting to do the same
thing.  There is a class with a static member (wrapper) which is
overloaded based on a function template type (i.e. R func()).

I can't understand why the second section errors out.  It seems like
the enable_if should be able to overload the member function types
within the same class definition.

Any help, explanations would be appreciated.

Thanks,
Oz

PS.  I've provided is_void and enable_if_c which are basically like
boost's but allow simple standalone compilation of this program with
any C++ compiler.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <iostream>

// is_void type trait
template <typename T> struct is_void { static const bool value =
false; };
template <> struct is_void<void> { static const bool value = true; };

// enable_if_c like boost
template <bool b, typename T> struct enable_if_c {};
template <typename T> struct enable_if_c<true, T> { typedef T type; };

// some simple functions
void foo() { std::cout << "foo\n"; }
int bar() { std::cout << "bar\n"; return 42; }

#if 1

// this works

template <typename R, typename enable = void> struct obj;

template <typename R>
struct obj<R, typename enable_if_c<is_void<R>::value, void>::type>
{
   template <R func()> static void wrapper() { func(); }
};

template <typename R>
struct obj<R, typename enable_if_c<!is_void<R>::value, void>::type>
{
   template <R func()> static void wrapper()
   {
     std::cout << "non-void: " << func() << std::endl;
   }
};

#else

// this doesn't work

template <typename R>
struct obj {
   template <R func()>
   static typename enable_if_c<is_void<R>::value, void>::type wrapper()
   {
     func();
   }

   template <R func()>
   static typename enable_if_c<!is_void<R>::value, void>::type wrapper
()
   {
     std::cout << "non-void: " << func() << std::endl;
   }
};

#endif

int main()
{
   obj<void>::wrapper<foo>();
   obj<int>::wrapper<bar>();
   return 0;
}

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply ozrictentacle1 (2) 1/20/2010 8:14:55 AM

On 20/01/10 14:14, Oz wrote:
> Hi All,
> I was wondering if someone can give me assistance with the following
> small program.  There are two sections controlled by an #if.  The
> first section compiles and runs correctly (using g++), the alternative
> section errors out.  Both sections are attempting to do the same
> thing.  There is a class with a static member (wrapper) which is
> overloaded based on a function template type (i.e. R func()).
>
> I can't understand why the second section errors out.  It seems like
> the enable_if should be able to overload the member function types
> within the same class definition.
>
> Any help, explanations would be appreciated.
>
> Thanks,
> Oz
>
> PS.  I've provided is_void and enable_if_c which are basically like
> boost's but allow simple standalone compilation of this program with
> any C++ compiler.
>
> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
>
> #include<iostream>
>
> // is_void type trait
> template<typename T>  struct is_void { static const bool value =
> false; };
> template<>  struct is_void<void>  { static const bool value = true; };
>
> // enable_if_c like boost
> template<bool b, typename T>  struct enable_if_c {};
> template<typename T>  struct enable_if_c<true, T>  { typedef T type; };
>
> // some simple functions
> void foo() { std::cout<<  "foo\n"; }
> int bar() { std::cout<<  "bar\n"; return 42; }
>
> #if 1
>
> // this works
>
> template<typename R, typename enable = void>  struct obj;
>
> template<typename R>
> struct obj<R, typename enable_if_c<is_void<R>::value, void>::type>
> {
>     template<R func()>  static void wrapper() { func(); }
> };
>
> template<typename R>
> struct obj<R, typename enable_if_c<!is_void<R>::value, void>::type>
> {
>     template<R func()>  static void wrapper()
>     {
>       std::cout<<  "non-void: "<<  func()<<  std::endl;
>     }
> };
>
> #else
>
> // this doesn't work
>
> template<typename R>
> struct obj {
>     template<R func()>
>     static typename enable_if_c<is_void<R>::value, void>::type wrapper()
>     {
>       func();
>     }
>
>     template<R func()>
>     static typename enable_if_c<!is_void<R>::value, void>::type wrapper
> ()
>     {
>       std::cout<<  "non-void: "<<  func()<<  std::endl;
>     }
> };

This is because the return type of wrapper function does not depend on
the function deduced template argument, rather R is known at class
template instantiation time. SFINAE works at function template
instantiation time and requires deduced types of function arguments.

>
> #endif
>
> int main()
> {
>     obj<void>::wrapper<foo>();
>     obj<int>::wrapper<bar>();
>     return 0;
> }
>

You can achieve the desired effect without SFINAE here, using only
function overloading:

[max@truth test]$ cat test.cc
#include <iostream>

// some simple functions
void foo() { std::cout << "foo"; }
int bar() { std::cout << "bar"; return 42; }

template<class T> struct Type {};

template<class R>
struct obj {
     template<R func()>
     static R wrapper()
     {
         return doWrapper<func>(Type<R>());
     }

     template<R func()>
     static R doWrapper(Type<void>)
     {
         std::cout << "void: ";
         func();
         std::cout << '\n';
     }

     template<R func(), class T>
     static R doWrapper(Type<T>)
     {
         std::cout << "non-void: ";
         R r = func();
         std::cout << " = " << r << '\n';
         return r;
     }
};

int main()
{
    obj<void>::wrapper<foo>();
    obj<int>::wrapper<bar>();
    return 0;
}

[max@truth test]$ g++ -Wall -o test test.cc
[max@truth test]$ ./test
void: foo
non-void: bar = 42

-- 
Max

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Maxim 1/21/2010 8:14:21 PM


1 Replies
156 Views

(page loaded in 0.209 seconds)


Reply: