Re: Templates and overloading problem
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! ]