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.
Related
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";
}
};
I'm trying to use template specialization to return different types based on the value of the template variable.
I've moved from trying to branch at runtime rather than compile time using typeof(), unspecialized templates and using std::enable_if_t<>. I think this may stem from a lack of understanding about how the template functions are resolving.
class Test
{
public:
template <typename T>
T request()
{
T ret = getVal<T>();
return ret;
}
private:
float foo = 2.f;
int bar = 1;
template <typename T>
typename std::enable_if<std::is_same<T, float>::value, bool>::type
getVal() { return foo; }
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, bool>::type
getVal() { return bar; }
template<typename T>
T getVal()
{
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
};
int main()
{
Test t;
int i;
float f;
i = t.template request<int>();
f = t.template request<float>();
}
I'm expecting this to resolve to three different functions, but I'm not sure if it is:
T Test::getVal()
int Test::getVal()
float Test::getVal()
Any help would be greatly appreciated.
You can do this pretty easily by specializing getVal(), though you may have oversimplified the question
class Test {
public:
template <typename T>
T request() {
T ret = getVal<T>();
return ret;
}
private:
float foo = 2.f;
int bar = 1;
template<typename T>
T getVal() {
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
};
// add specializations
template<>
float Test::getVal<float>() { return foo; }
template <>
int Test::getVal<int>() { return bar; }
int main() {
Test t;
int i = t.request<int>(); // don't need template keyword here
float f = t.request<float>();
}
If you're able to use c++17, it is even simpler with if constexpr and a single getVal
template<typename T>
auto getVal() {
if constexpr (std::is_same_v<int, T>) {
return foo;
} else if constexpr (std::is_same_v<float, T>) {
return bar;
} else {
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
}
Your problem is that template<typename T> T getVal() make call ambiguous when the SFINAEd one succeed.
One solution is to restrict that one with complement condition...
But tag dispatching is an easy alternative way to fix your issue:
template <typename> struct Tag{};
class Test
{
public:
template <typename T>
T request() const
{
return getVal(Tag<T>{});
}
private:
float foo = 2.f;
int bar = 1;
float getVal(Tag<float>) const { return foo; }
int getVal(Tag<int>) const { return bar; }
template<typename T> void getVal(Tag<T>) = delete;
};
I'm working on a C++11 wrapper around a C api. The C api offers a bunch of getters for various types, with a different name for each type. Values are retrieved by array of a given size, known at compilation.
I want to give the type and the array size by template, to call the right function.
#include <string>
#include <iostream>
template <typename T>
struct make_stop {
constexpr static bool value = false;
};
class Foo
{
public:
Foo() : i(42) {}
template<typename T, size_t n>
T get();
private:
int i = 0;
};
template<typename T, size_t n>
T Foo::get() { static_assert(make_stop<T>::value); return T(); }
template<int, size_t n>
int Foo::get() { return i + n; }
int main() {
Foo foo;
int i = foo.get<int, 4>();
double f = foo.get<double, 2>();
return 0;
}
But it fails to match the right function
main.cpp:26:5: error: no declaration matches 'int Foo::get()'
int Foo::get() { return i + n; }
^~~
main.cpp:15:7: note: candidate is: 'template<class T, long unsigned int n> T Foo::get()'
T get();
its a bit vauge from your question, but assuming you are wanting to index into some c- arrays and return the value at I you can't specialize function templates like you want, but you can use some tags instead, something like..
class Foo
{
public:
Foo() : is{1,2,3,4,5,6,7,8,9,10},ds{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1} {}
template <typename T> struct type_c{};
template <size_t I> struct int_c{};
template<typename T,size_t I>
auto get()
{ return get_impl(type_c<T>(),int_c<I>()); }
private:
template <size_t I>
auto get_impl(type_c<int>,int_c<I>)
{ return is[I]; }
template <size_t I>
auto get_impl(type_c<double>,int_c<I>)
{ return ds[I]; }
int is[10];
double ds[10];
};
int main() {
Foo foo;
int i = foo.get<int,0>();
double d = foo.get<double,2>();
std::cout << i << " " << d << std::endl;
return 0;
}
Demo
If I understood you correctly you want to partially specialize get for T. Unfortunately partial specialization for methods is not allowed by the standard. You can however get around this with a static method on a class templated by T and specializing the class.
Like this:
template <class T> struct Foo_helper;
struct Foo
{
Foo() : i{42} {}
template<class T, std::size_t N>
T get()
{
return Foo_helper<T>::template get<N>(*this);
}
int i = 0;
};
template <class T> struct Foo_helper {};
// specialize Foo_helper for each type T you wish to support:
template <> struct Foo_helper<int>
{
template <std::size_t N>
static int get(const Foo& foo) { return foo.i + N; }
};
template <> struct Foo_helper<double>
{
template <std::size_t N>
static double get(const Foo& foo) { return foo.i + N; }
};
int main()
{
Foo foo{};
int i = foo.get<int, 4>();
double d = foo.get<double, 2>();
}
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> >();
}
Say I want to write a wrapper for 2 or more classes that do the same things with different implementations and their interfaces have different function names. Depending on the context I would choose the one or the other, but I want to be able to easily switch them out. SO I write a wrapper with template specialization. Ok good. Now however I encountered a problem. My 2 classes are template classes...
If they were normal classes I could write code like this:
class A1
{
public:
int f()
{
return 1;
}
};
class A2
{
public:
int g()
{
return 1;
}
};
namespace detail
{
template <class T> int h(T& t) // general case
{
std::cout << "general" << "\n";
return t.h();
}
template <> int h<A1>(A1& a1) // case for A1
{
std::cout << "A1" << "\n";
return a1.f();
}
template <> int h<A2>(A2& a2) // case for A2
{
std::cout << "A2" << "\n";
return a2.g();
}
}
template <class T>
class Wrapper
{
public:
Wrapper(T& t) : t(t) {}
int operator()()
{
return detail::h<T>(t);
}
T& t;
};
However, how would I need to modify that code to make it run for tempalted versions of A1 and A2? The best I came up with was this (does not compile):
template <class T>
class A1
{
public:
int f()
{
return 1;
}
};
template <class T>
class A2
{
public:
int g()
{
return 1;
}
};
namespace detail
{
template <class T, class U> int h(T<U>& t) // general case
{
return t.h();
}
template <> int h<A1<U>>(A1<U>& a1) // case for A1
{
return a1.f();
}
template <> int h<A2<U>>(A2<U>& a1) // case for A2
{
return a1.f();
}
}
template <class T, class U>
class Wrapper
{
public:
Wrapper(T<U>& t) : t(t) {}
int operator()()
{
return detail::h<T,U>(t);
}
T<U>& t;
};
So, I somehow need to template the template specializations, which sounds like a contradiction.
edit
Ok.. trying to make the overload solution work, but I don't really get it...
template <template <typename> class T, class U>
class Wrapper
{
public:
Wrapper(T<U>& t) : t(t) {}
template <template <typename> class T, typename U>
int h(T<U>& t) // general case
{
return t.h();
}
template <typename U>
int h(A1<U>& a1) // case for A1
{
return a1.f();
}
template <typename U>
int h(A2<U>& a2) // case for A2
{
return a2.g();
}
T<U>& t;
};
Prefer overload to template specialisation:
template <template <typename> class T, typename U>
int h(T<U>& t) // general case
{
return t.h();
}
template <typename T>
int h(A1<T>& a1) // case for A1
{
return a1.f();
}
template <typename T>
int h(A2<T>& a2) // case for A2
{
return a2.g();
}