Partial specialization for member functions template arguments? - c++

Partial specialization for member functions template arguments is possible? I'm not sure, but it is worth a try.
This works just fine (http://coliru.stacked-crooked.com/a/795e953af7537ab6):
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename TClass, void(TClass::*t_func)()>
void function()
{
TClass p;
(p.*t_func)();
}
template <typename TClass, void(TClass::*t_func)(), typename TClass2, void(TClass2::*t_func2)(), typename ...Rest>
void function()
{
function<TClass, t_func>();
function<TClass2, t_func2, Rest...>();
}
int main()
{
function<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
Output:
Bar()
Bar2()
The next sample also works (http://coliru.stacked-crooked.com/a/e8fe14dde6932f4c):
#include <iostream>
struct Foo { Foo() { std::cout << "Foo()" << std::endl; } };
struct Foo2 { Foo2() { std::cout << "Foo2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){ std::cout << "EmptyImpl" << std::endl; }
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, Foo2>();
}
Output:
Foo()
Foo2()
EmptyImpl
But if I want to combine these two things above:
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, void(TClass::*t_func)(), typename ...Rest>
struct Impl<TClass, decltype(t_func), Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
it will be a compiler error:
main.cpp: In function 'int main()':
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
main.cpp:36:59: note: expected a type, got '&Foo::Bar'
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
main.cpp:36:59: note: expected a type, got '&Foo2::Bar2'
Any idea? What did I miss? :)

consider using additional wrapper for calling member functions
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <class TClass>
using FType = void(TClass::*)();
template<class TClass, FType<TClass> t_func>
class Caller
{
public:
Caller()
{
TClass p;
(p.*t_func)();
}
};
template <typename... Args>
struct Impl;
template <class TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <class ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Caller<Foo, &Foo::Bar>, Caller<Foo2, &Foo2::Bar2> >();
}

Related

Why SFINAE report error in function overloading

Follwing code can't compile,I just want testing SFINAE,why it can't compile?
#include <type_traits>
template<typename T>
class TestVoid {
template<std::enable_if_t<std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<std::enable_if_t<!std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};
int main() {
TestVoid<void> t;
return 0;
}
The problem is the conditions of std::enable_if don't depend on template parameter of func themselves.
You might change the code to
template<typename T>
struct TestVoid {
template<typename X = T, std::enable_if_t<std::is_void_v<X>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename X = T, std::enable_if_t<!std::is_void_v<X>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};
LIVE
When you instantiate the class template, all of the member function declarations must be valid. In your case, one of them won't be. Instead, you can delegate func to another function template.
live link
template<typename T, std::enable_if_t<std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename T, std::enable_if_t<!std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "none void\n";
}
template<typename T>
class TestVoid {
public:
void func_member() {
func<T>();
}
};
Or, if you want to keep the actual implementation of func as a member function:
live link
template<typename T>
class TestVoid {
public:
void func_member() {
func<T>();
}
private:
template<typename U, std::enable_if_t<std::is_void_v<U>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename U, std::enable_if_t<!std::is_void_v<U>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};

C++ Enum Template Functions: Compile Time Reflection

in principle the question is about the best way of getting reflexive iteration over an enum at compile time.
Let's assume I have an enum
enum Animal {
DOG = 0,
CAT = 12,
};
Now I have a function template
template <Animal A>
void animalVoice();
And I specialise the template:
template <>
void animalVoice<DOG>() {cout << "Bau" << endl;}
template <>
void animalVoice<CAT>() {cout << "Meow" << endl;}
Do I have the possibility of getting the same behaviour as in
int main() {
animalVoice<DOG>;
animalVoice<CAT>;
return 0;
}
By iterating at compile time over the value of the enum?
Thanks
M.
You might have an animal container:
enum Animal {
DOG = 0,
CAT
};
constexpr auto all_animals = std::integer_sequence<Animal, DOG, CAT>{};
and then
template <Animal... Args>
void call_animalVoice()
{
(animalVoice<Args>(), ...);
}
template <Animal... Args>
void call_animalVoice(integer_sequence<Animal, Args...>)
{
// (animalVoice<Args>(), ...);
call_animalVoice<Args...>();
}
with call:
call_animalVoice(all_animals)
or maybe std::tuple
constexpr auto all_animals = std::tuple<
std::integral_constant<Animal, DOG>,
std::integral_constant<Animal, CAT>
>{};
and
std::apply([](auto... animals){ (animalVoice<decltype(animals){}()>(), ...);
}, all_animals);
If you allow enumerating from 0 incrementaly then integer_sequence would work:
#include <iostream>
#include <utility>
using namespace std;
enum Animal {
DOG = 0,
CAT,
NUM_ANIMALS
};
template <Animal A>
void animalVoice();
template <>
void animalVoice<DOG>() { cout << "Bau" << endl; }
template <>
void animalVoice<CAT>() { cout << "Meow" << endl; }
template <size_t... Args>
void call_animalVoice()
{
(animalVoice<static_cast<Animal>(Args)>(), ...);
}
template <size_t... Args>
void call_animalVoice(integer_sequence<size_t, Args...>)
{
call_animalVoice<Args...>();
}
int main()
{
call_animalVoice(make_integer_sequence<size_t, NUM_ANIMALS>{});
}
Live Demo on Wandbox

Calling template function from inner class

I have a class like this to call a function depending on the type. I try to compile it, but have error error C2059 syntax error : 'template'
class A
{
call_1()
{
B<type> b;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
return word;
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
/**/
}
};
}
What am I doing wrong?
First, let's rewrite your example into something that is readable and is closer to being compilable, and we also print "1" or "2" in say() to know which function gets called:
#include <iostream>
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
};
OK, so first, you are trying to specialize B inside of A. This is not allowed, so let't move it outside of A:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
Next up, you are using the same template parameter (T) in both B and say(). You don't need to repeat T, so let's delete it:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
Finally, call_1() cannot be defined before the specialization of A::B, so we need to move it outside too:
using type = int;
class A {
void call_1();
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
void A::call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
This should now compile and do what you want. Calling call_1() will print 1. If you change the type from int to void:
using type = void;
it will print 2.

How to use functor as a member in class template?

I was trying to use a functor as a std::function object inside a class template. Below is what I have done so far.
//! the functor class template
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << t << "\n";
}
};
//! the class template that holds a std::function object as a member
template<typename T>
struct Foo
{
std::function<void(T)> bar = func<T>();
};
int main()
{
Foo<int> foo;
return 0;
}
It was complained that
error: conversion from 'func<int>' to non-scalar type 'std::function<void(int)>' requested
struct Foo
^
Is it possible to do so? How to fix it?
You can either make it static and initialize it outside class-scope, or initialize it in the constructor. Tested on GCC 4.7.2.
template<typename T>
struct Foo
{
static std::function<void(T)> bar;
};
template <typename T>
std::function<void(T)> Foo<T>::bar = func<T>();
EDIT
In C++11, you can also use brace-initialization:
std::function<void(T)> bar { func<T>() };
Different ways to use std::function in a non-static data member initializer
#include <functional>
#include <iostream>
#define ENABLE_CONVERSION 1
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << "Function: " << t << "\n";
}
#if ENABLE_CONVERSION
// FIX: error: conversion from ‘func<int>’ to non-scalar type
// ‘std::function<void(int)>’ requested
operator std::function<void(T)> () { return std::function<void(T)>(*this); }
#endif
};
template<typename T>
struct Foo
{
std::function<void(T)> bar0 = std::function<void(T)>(func<T>());
std::function<void(T)> bar1{func<T>()};
// Error without ENABLE_CONVERSION
std::function<void(T)> bar2 = func<T>();
static std::function<void(T)> bar3;
void operator() () {
bar0(0);
bar1(1);
bar2(2);
bar3(3);
}
};
template<typename T>
std::function<void(T)> Foo<T>::bar3 = func<T>();
template<typename T>
void goo() {
// This compiles without ENABLE_CONVERSION:
// What is the difference to non-static data member initializers ?
std::function<void(T)> g = func<T>();
g(4);
}
int main()
{
Foo<int> foo;
foo();
goo<int>();
return 0;
}
Additional question
I tried to find differences between variable brace-or-equal-initializer
and the non-static data member brace-or-equal-initializer. I found nothing.
What is the difference between
std::function<void(T)> bar2 = func<T>();
and
std::function<void(T)> g = func<T>();
when ENABLE_CONVERSION is zero?
In your case std::function is optional, use direct functor itself.
//! the functor class template
template<typename T>
struct func
{
void operator ()(T t)
{
std::cout << t << "\n";
}
};
//! the class template that holds a std::function object as a member
template<typename T>
struct Foo
{
//std::function<void(T)> bar = func<T>(); <-- **removed, because std::function isn't cheap as func<T>**.
func<T> bar;//default initialized itself.
};
int main()
{
Foo<int> foo;
foo.bar(24);//prints 24.
return 0;
}
EDIT:
In common case, move template from struct declration to the operator, i.e. as:
struct func
{
template< typename T >
void operator()(T t ) const { std::cout << t << '\n'; }
};
struct Foo
{
func m_func;
};
int main(){
Foo f;
f.m_func(24); // prints 24
f.m_func("hello world"); // prints "hello world"
f.m_func(3.143); // prints 3.143
// and etc.,
};
in c++14, std::less<>, std::greater<> and more other functors template keyword moved to the operator declaration, instead of struct declaration, it's help more generic comparation.
Edit2: You may use following technicus:
struct func{
template< typename T > void operator()(T t) const{ std::cout << t << '\n';}
};
template< typename T, typename Functor> // Functor as template
struct Foo
{
Functor m_Functor; //--> functor member
T m_Data; // or something else.
};
// create `makeFoo` for auto deduced functor type.
template< typename T, typename Functor>
Foo<T,Functor> makeFoo(Functor f, T t ) { return {f,t}; }
int print(int i, int j){ std::cout << i+j << '\n' ;}
int main()
{
auto foo = makeFoo(24, func{} );
// use foo
auto foo2 = makeFoo("hello", std::bind(print, 2, _1) );
// use foo2
}

Is it possible to write specialization for member function of a template class?

template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
void A<T, true>::f<T, true>()
{
std::cout << "true" << std::endl;
}
The code above is wrong and don't compile, but you get the idea of what I'm going to do. So how should I do that?
You can't specialize just one method of a class. Usually you can solve that with a template nested class on the same T.
template <class T, bool flag>
class A
{
//...
template <class Q, bool flag>
class F_Helper
{
void operator()()
{
std::cout << "false" << std::endl;
}
};
template <class Q>
class F_Helper<Q, true>
{
void operator()()
{
std::cout << "true" << std::endl;
}
};
F_Helper<T> f;
//...
};
Obviously a bit more boilerplate is needed if you do need access to the enclosing class' this pointer.
Contrary to what the other answers say, you can specialize a member function of a class template. But you need to provide all template arguments
template<>
void A<int, true>::f()
{
std::cout << "true" << std::endl;
}
What you try is not valid:
template<typename T>
void A<T, true>::f()
{
std::cout << "true" << std::endl;
}
Partially specializing a member of a class template for particular arguments of that class template is not valid, so that means "define the member function 'f' of a partial specialization of A for <T, true>". Because there is no such partial specialization, the compiler will error out.
If you cannot provide all arguments, you can overload f as follows
template <class T, bool flag>
class A
{
template<typename, bool> struct params { };
void f()
{
f(params<T, flags>());
}
template<typename U>
void f(params<U, true>) {
std::cout << "true" << std::endl;
}
template<typename U, bool flag1>
void f(params<U, flag1>) {
std::cout << "dunno" << std::endl;
}
};
You can specialize whole template class - Ideone link
#include <iostream>
template <class T, bool flag>
class A
{
//...
void f()
{
std::cout << "false" << std::endl;
}
//...
};
template<class T>
class A<T, true>
{
//...
void f()
{
std::cout << "true" << std::endl;
}
//...
};
You need to specialize the whole class:
#include <iostream>
template <class T, bool flag>
class A
{
public:
void f()
{
std::cout << "false" << std::endl;
}
};
template<class T>
class A<T,true>
{
public:
void f()
{
std::cout << "true" << std::endl;
}
};
void main()
{
A<int, false> a;
a.f();
A<int, true> b;
b.f();
}