C++ specialise function on enum - c++

Is it possible to specialise a template function on an enum?
I've seen noted here a template function can be disabled if it isn't an enum, but is this possible whilst still allowing other types?
My example below shows specialisations for int, float, and enum (it doesn't compile because it tries to overload the enum version rather than specialising it). I feel I'm missing something obvious.
Note that I'm looking to specialise on any enum, not just a named one (EAnEnum in the example)
#include <iostream>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename T>
void MyFunc();
template<>
void MyFunc<int>()
{
std::cout << "Int" << std::endl;
}
template<>
void MyFunc<float>()
{
std::cout << "Float" << std::endl;
}
// MyFunc<Enum>
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type MyFunc()
{
std::cout << "Enum" << std::endl;
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}

You cannot partially specialize a function, but you can use tag dispatching instead.
It follows a minimal, working example based on the OP's question:
#include <iostream>
#include<type_traits>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename>
struct tag {};
void MyFunc(tag<int>)
{
std::cout << "Int" << std::endl;
}
void MyFunc(tag<float>)
{
std::cout << "Float" << std::endl;
}
void MyFunc(tag<EAnEnum>)
{
std::cout << "Enum" << std::endl;
}
template<typename T>
void MyFunc() {
MyFunc(tag<std::decay_t<T>>{});
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}
You can easily add a parameter pack to be forwarded to the right MyFunc and still use this technique to solve your problem.
Of course, you can now specialize for any enum.
You can also provide a fallback MyFunc as:
template<typename T>
void MyFunc(tag<T>)
{
std::cout << "Fallback" << std::endl;
}
If you want a fallback for all the possible enum types, you can now rely on SFINAE, for these are different overloaded functions:
template<typename T>
std::enable_if_t<std::is_enum<T>::value>
MyFunc(tag<T>)
{
std::cout << "Fallback for enums only" << std::endl;
}
Note that you should not use directly the implications of MyFunc that accept a tag specialization as an entry point.
Those are meant as internal functions.
Use instead the generic one, as shown in the example.

You cannot partially specialize a function template, but can you just let it forward to a class template.
Since your function doesn't have arguments that's particularly easy:
#include <iostream>
#include <type_traits>
namespace impl {
using namespace std;
template< class Type, bool is_enum_ = is_enum<Type>::value >
struct Foo;
template< class Type >
struct Foo<Type, true>
{ void func() { cout << "Enum" << endl; } };
template<>
struct Foo<int>
{ void func() { cout << "Int" << endl; } };
template<>
struct Foo<float>
{ void func() { cout << "Float" << endl; } };
} // namespace impl
template< class Type >
void foo()
{ impl::Foo<Type>().func(); }
auto main()
-> int
{
enum class An_enum
{
alpha, beta,
};
foo<An_enum>();
foo<int>();
foo<float>();
#ifdef TEST
foo<char>(); //! Doesn't compile.
#endif
}
With arguments you can use “perfect forwarding” (which isn't all that perfect, really, but usually good enough) via std::forward.

Related

How do member variables work with specialized class templates?

I'm trying to write a very simple specialized class template that has a member variable and can print that member variable differently in specialized situations. I know the example is pretty useless, but it illustrates the question pretty well.
When specializing class templates it seems that the specializations of the class don't share the same member variables, so the following code won't compile...
#include <iostream>
#include <string>
// Class template
template <typename T>
struct S
{
S(const T& t)
: t(t)
{}
void print()
{
std::cout << t << std::endl;
}
private:
T t;
};
// Specialization
template <>
struct S<std::string>
{
void print()
{
// ERROR: "t" is not defined in this context
std::cout << "string: " << t << std::endl;
}
};
This suggests that I would need to write a separate constructor for every specialization and have a separate member variable t for each specialization which feels like it would quickly become a lot of duplicated code and effort if I have many specializations.
If what I am saying is true, then is it bad practice to use member variables in specialized class templates altogether? Are there any alternatives that result in less code duplication?
Please also look at #0x499602D2's answer, it is simpler and works for many practical cases.
You are correct, the specializations are basically totally independet from each other and the original template, so you would have to write everything new. A way to get around that would be to use inheritance.
#include <iostream>
#include <string>
// Class template
template <typename T>
struct Base
{
Base(const T& t)
: t(t)
{}
virtual void print()
{
std::cout << t << std::endl;
}
protected:
T t;
};
template<class T>
struct S: Base<T> {
};
// Specialization
template <>
struct S<std::string>: Base<std::string>
{
void print() override
{
std::cout << "string: " << t << std::endl;
}
};
Since you are only specializing a single template parameter, you can explicitly specialize the member function instead of the entire class:
template <>
void S<std::string>::print()
{
std::cout << "string: " << t << std::endl;
}
Another possible solution is tag-dispatcing
template <typename T>
struct S
{
private:
T t;
void print_helper (std::true_type) // T is std::string
{ std::cout << "string: " << t << std::endl; }
void print_helper (std::false_type) // T isn't std::string
{ std::cout << t << std::endl; }
public:
S (T const & t0) : t{t0}
{ }
void print ()
{ print_helper(std::is_same<T, std::string>{}); }
};
Another way to do it is to use a helper function. This will let you do partial template specialization kind of, working around the issue noted by #0x499602D2. What we're doing is having the templated function call a helper function and the helper function is doing all the specialization.
I added another template parameter into there to show that this solution kind of works for partial template specialization. Notice that the templated helper function is full-specialized, not partially. You can't partially specialize a function. This can be useful in cases when the class template has more template parameters that you can't specialize (UNUSED_T) but the function that you do want to specialize can be fully specialized (print_it doesn't need the UNUSED_T).
#include <iostream>
#include <string>
// This is the helper function for all types T...
template <typename T>
void print_it(T t) {
std::cout << t << std::endl;
}
// ... except for std::string, it will run this one.
template <>
void print_it<std::string>(std::string t) {
std::cout << "string: " << t << std::endl;
}
// Class template, UNUSED is there just to show that
// this works for partial template specialization.
template <typename T, typename UNUSED_T>
struct S {
S(const T& t) : t(t) {}
void print() {
// You can remove the <T> because
// the compiler will figure it out for you.
print_it<T>(t);
}
prviate:
T t;
UNUSED_T unused;
};
int main() {
S<uint, char> x(5);
x.print(); // OUTPUT: 5
S<std::string, char> y("foo");
y.print(); // OUTPUT: string: foo
}

template friend function: wrong function called

I'm trying to overload a function inside template struct using friend.
I want to use that to map a type to another type. Here in the code below I want to map the type int to MyType.
Here's what I did so far:
void map(...){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
friend Type map(T) { return {}; }
};
// Make the function with int?
struct MyType : MakeFunction<MyType, int> {};
int main() {
// The type obtained is void, worst case choosed. The expected result is `MyType` as return type.
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
return 0;
}
Then, I tried that:
template<typename T>
void map(){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
// Compilation error.
friend Type map<T>() { return {}; }
};
struct MyType : MakeFunction<MyType, int> {};
int main() {
std::cout << typeid(decltype(map<int>())).name() << std::endl;
return 0;
}
But the compilation failed with :
error: defining explicit specialization ’map<T>’ in friend delcaration
How can I change the declaration so the right function is picked? Or is there a way to map types without a ton a boilerplate?
Below code shows how you can define a macro DEFINE_TYPE_MAPPING meeting your needs (this is to some extent a sketch demonstrating the idea):
#include <iostream>
#include <typeinfo>
void map(...){} // Worst case
template<class T> struct TypeMapping;
template<class T>
typename TypeMapping<T>::type map(const T&);
#define DEFINE_TYPE_MAPPING(T, U) \
template<> struct TypeMapping<T> { typedef U type; };
struct MyType {};
DEFINE_TYPE_MAPPING(int, MyType);
DEFINE_TYPE_MAPPING(char, float*);
DEFINE_TYPE_MAPPING(std::ostream, unsigned long);
int main() {
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
std::cout << typeid(decltype(map('c'))).name() << std::endl;
std::cout << typeid(decltype(map(std::cout))).name() << std::endl;
std::cout << typeid(decltype(map(1.0))).name() << std::endl;
return 0;
}
How about:
namespace detail{
// To keep exact type
template <typename> struct tag {};
// The mapping
float map(tag<char>);
MyType map(tag<int>);
char map(tag<const int&>);
// ... and so on
}
template <typename T>
using map_t = decltype(detail::map(detail::tag<T>{}));
And then
int main() {
std::cout << typeid(map_t<int>).name() << std::endl;
std::cout << typeid(map_t<const int&>).name() << std::endl;
}

variadic template unpacking arguments to typename

I want to unpack the parameter pack in func (see line A), but it doesnt work. How can I unpack inside func< > or modify Line A only?
#include <iostream>
using namespace std;
void func()
{
cerr << "EMPTY" << endl;
}
template <class A, class ...B> void func()
{
cerr << "A: " << endl;
func<B... >(); // line A
}
int main(void)
{
func<int,int>();
return 0;
}
An expected output :
A:
A:
edited:
all of answers are very good. thanks alot
Sometimes it's easier to unpack everything at once, instead of recursively. If you simply want a parameter pack for_each, you can use a variant of the braced-init-list expansion trick (Live demo at Coliru):
template <class A>
void process_one_type() {
cerr << typeid(A).name() << ' ';
}
template <class ...B> void func()
{
int _[] = {0, (process_one_type<B>(), 0)...};
(void)_;
cerr << '\n';
}
By using func<B... >(); you are implying that func is a function template, but your previously defined func() is not.
You need to define a func() template that accepts zero template arguments. Here's a working example (on g++ 4.8.1):
#include <iostream>
using namespace std;
void func()
{
cerr << "EMPTY" << endl;
}
template <class ... B>
typename std::enable_if<sizeof...(B) == 0>::type func()
{
}
template <class A, class ...B> void func()
{
cerr << "A: " << endl;
func<B... >(); // line A
}
int main(void)
{
func(); // This outputs EMPTY
func<int,int>(); // This will not output EMPTY
return 0;
}
Try this:
template <class A> void func()
{
cerr << "A: " << endl;
}
template <class A, class B, class ...C> void func()
{
cerr << "A: " << endl;
func<B, C...>(); // line A
}
Consider what the invocation of the recursive call func<B...>(); looks like when B... is empty. It's calling func<>(); but the definition of your attempted base case func() is not a template function, ie. you can't call it via func<>();
Since we don't have partial specialization for function templates yet, (hopefully it will be supported soon) one way to do it is to use a class template to do the partial specialization and use the function to simply delegate the work to the class template.
#include <iostream>
/* Forward declaration. */
template <typename... T>
struct FuncImpl;
/* Base case. */
template <>
struct FuncImpl<> {
void operator()() const {
std::cout << "Base case" << std::endl;
}
}; // FuncImpl<>
/* Recursive case. */
template <typename First, typename... Rest>
struct FuncImpl<First, Rest...> {
void operator()() const {
std::cout << "Recursive case" << std::endl;
FuncImpl<Rest...>()();
}
}; // FuncImpl<First, Rest...>
/* Delegate function. */
template <typename... T>
void Func() {
FuncImpl<T...>()();
}
int main() {
Func<>();
Func<int, double>();
}
Personally I think this solution is cleaner than other solutions such as tagged dispatching or SFINAE, despite the cruft around operator()s.

Invalid use of incomplete type (SFINAE)

I am trying to use some SFINAE inside a templated struct. I reduced my problem to the following and could make this work:
template<bool mybool>
struct test {
void myfunc();
};
template<bool mybool>
void test<mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<>
void test<false>::myfunc() {
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<true> foo;
test<false> bar;
foo.myfunc();
bar.myfunc();
}
With this code, I get the result:
test true
test false
However, if I want to consider that my struct test with more than one template parameter, I tried adapting the above like this:
template<int myint, bool mybool>
struct test {
void myfunc();
};
template<int myint, bool mybool>
void test<myint,mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<int myint>
void test<myint,false>::myfunc() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.myfunc();
bar.myfunc();
}
I am getting an invalid use of incomplete type 'struct test'.
Am I going in the wrong direction? Is there a way to do what I want to do?
Thanks for your help!
You cannot partially specialize member function, you should partially specialize full struct. Following example will work correctly
template<int myint, bool mybool>
struct test {
void my_func();
};
template<int myint, bool mybool>
void test<myint,mybool>::my_func() {
std::cout << "test true" << std::endl;
}
template<int myint>
struct test<myint, false> {
void my_func();
};
template<int myint>
void test<myint,false>::my_func() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.my_func();
bar.my_func();
}
If you want to avoid redefining your class, which you would have to do since partial specialisation of (member) functions is not allowed, you could decompose your type. This will minimise the repetition of code:
template<int myint, bool mybool>
struct test {
char some_var;
std::vector<int> more_var;
void my_func();
};
Change to:
template<int myint>
struct test_static {
protected:
char some_var;
std::vector<int> more_var;
};
template <int myint, bool mybool>
struct test : private test_static<myint> {
void my_func() {
// default case
}
};
template <int myint>
struct test<myint,false> : private test_static<myint> {
void my_func() {
// special case
}
};
Of course, if you want full visibility of all members to the outside, don't make them protected in the first place and use public instead of private inheritance.
Looking first at this question on the SFINAE principle to refresh my memory, I tried to get the result you are looking for with minimal redundancy in the code.
I also checked the wikipedia article on the subject, which indicated me that you need a functionality similar too boost::enable_if to conditionally choose your function inmplementation:
// simplified version of boost::enable_if_c and disable_if_c to match your exact need
template <bool B>
struct enable_if_c {
typedef void type;
};
struct enable_if_c<false>{};
template <bool B>
struct disable_if_c {
typename void type;
};
struct disable_if_c<true> {};
template<bool mybool, typename T>
struct test {
template <bool d>
typename enable_if_c<d>::type my_func_impl(){
cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }
};
You can define the my_func_impl bodies outside the struct with the following syntax:
template <bool mybool, typename T>
template <bool d>
typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){
cout << "true" << endl;
}
The tricky point of the problem is that you cannot rely on a simple overloading, since you want the same function prototype, hence the need to exclusively define one or the other implementation.
You can add a little improvement to the answer provided by diderc, by just a little modification that enables you to avoid the use of an auxiliary function which would pollute your functions names :
Instead of :
template <bool d>
typename enable_if_c<d>::type my_func_impl(){
cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }
Just write :
template <bool d = mybool>
typename enable_if_c<d>::type my_func(){
cout << "true" << endl;
}
template <bool d = mybool>
typename disable_if_c<d>::type my_func(){
cout << "false" << endl;
}
And if you can use C++11, then you can replace enable_if_c and disable_if_c by std::enable_if.
( I can't comment his answer, so I posted my own )

partial specialization of function templates

In the below code snippet,
template<typename T1>
void func(T1& t)
{
cout << "all" << endl;
}
template<typename T2>
void func(T2 &t)
{
cout << "float" << endl;
}
// I do not want this
// template<> void func(float &t)
int main()
{
int i; float f;
func(i); // should print "all"
func(f); // should print "float"
return 0;
}
I would like to have the templates modified which by passing any type other than float will print "all" and passing float will print "float". I do not want template specialization, instead have partial specialization which will act accordingly based on input type. How should i go about it. Thanks in advance.
Well the scenario, i'm currently facing is like,
I need to have the following defined,
template<typename T1>
void func(T1 &t)
{
cout << "t1" << endl;
}
template<typename T2>
void func(T2 &t)
{
cout << "t2" << endl;
}
The following calls should print "t2"
func(int) // print "t2"
func(float) // print "t2"
func(string) // print "t2"
The following calls should print "t1"
func(char) // print "t1"
func(xyz) // print "t1"
...
func(abc) // print "t1"
some kind of grouping like the above where few should call the partial specialization implementation and others should call the default implementation.
You can combine function overloading with templates. So:
#include <iostream>
template<typename T>
void func(T& t)
{
std::cout << "all" << std::endl;
}
void func(float& f)
{
std::cout << "float" << std::endl;
}
int main()
{
int i; float f;
func(i); // prints "all"
func(f); // prints "float"
return 0;
}
Write a type traits class for your condition:
template<class T>
struct IsIntFloatOrString {
enum { value = boost::is_same<T, int>::value
or boost::is_same<T, float>::value
or boost::is_same<T, string>::value };
};
Use boost::enable_if and disable_if:
template<typename T1>
typename boost::enable_if<IsIntFloatOrString<T1> >::type
func(T1 &t) {
cout << "t1" << endl;
}
template<typename T2>
typename boost::disable_if<IsIntFloatOrString<T2> >::type
func(T2 &t) {
cout << "t2" << endl;
}
You cannot partially specialise functions in C++.
Perhaps this is not the terminology you mean. You can use templates like boost::is_same<T1, T2> to perform conditional logic based on the given template parameter. You can also use T in any place where you'd use any other type, such as in typeid(T).name():
template <typename T>
void foo(T&) {
if (boost::is_same<T, int>::value)
std::cout << "int lol";
else
std::cout << typeid(T).name();
}
(Although I'd not recommend using typeid().name() as its value is not specified by the standard and can vary from the type written in your code, to a mangled symbol, or the lyrics to Pokerface.)
Addendum Like other answerers, I would personally choose template specialisation itself or just plain ol' function overloading. I don't know why you're averse to them, but that is what they are there for.
As Tomalak already said in his answer you can not partially specialize a template function, but if you change your function to be a static member function in a template class, you could do it.
However, a better approach would be function overloading.
This is how to make it work without ugly syntax a and !b and !c for enable_if in case of arbitrary number of conditions.
If we know that partial specialization don't work work function but work with classes, let's use classes! We should hide it from people, but we can use them!
OK, code:
#include <type_traits>
#include <iostream>
template <typename T>
class is_int_or_float : public std::integral_constant<bool, std::is_same<T, int>::value || std::is_same<T, float>::value> {
};
template<typename T, typename Enable = void> //(2)
struct Helper {
static void go(const T&) {
std::cout << "all"<< std::endl;
}
};
template<typename T>
struct Helper<T, typename std::enable_if<is_int_or_float<T>::value>::type> { // (3)
static void go(const T&) {
std::cout << "int or float" << std::endl;
}
};
template<typename T>
struct Helper<T, typename std::enable_if<std::is_pointer<T>::value>::type> { // (3)
static void go(const T&) {
std::cout << "pointer" << std::endl;
}
};
template<typename T>
void func(const T& arg) {
Helper<T>::go(arg); // (1)
}
int main() {
char c;
int i;
float f;
int* p;
func(c);
func(i);
func(f);
func(p);
}
(1) First of all just for every type call helper. No specialization for functions.
(2) Here we add one dummy argument. We don't have to specify it on calling because it's default to void
(3) In 3 we just give void, when we allow T and anything else (or SFINAE as in our case). One important thing is that we shouldn't allow some T twice or more.
Notes:
We can also change default type to std::true_type, after that we will be able to get rid of std::enable_if (std::enable_if<some_trait<T>::value> will be change to just some_trait<T>::type). I'm not sure which
This code uses type traits from C++11. If you don't have c++11 support you may write your own traits or use type traits from boost
Live example