I want to create a function overload to partially specialize a template class. How to make this code work?
template <typename T>
struct Foo;
template <typename Result, typename ... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
Result t;
return t;
}
};
template <typename ... Args>
void Foo<void(Args...)>::Bar()
{
// do nothing;
}
If it's just a single member function that should expose different behavior if Result=void, then use tag-dispatching:
#include <type_traits>
template <typename T>
struct Foo;
template <typename Result, typename... Args>
struct Foo<Result(Args...)>
{
Result Bar()
{
return Bar(std::is_void<Result>{});
}
private:
Result Bar(std::false_type)
{
Result t;
// Do something
return t;
}
void Bar(std::true_type)
{
// Do nothing
}
};
DEMO
Alternatively, partially-specialize the whole class:
template <typename... Args>
struct Foo<void(Args...)>
{
void Bar()
{
// Do nothing
}
};
Related
I've got a problem with templates arguments. Here's the problem
template <typename T>
struct My_struct
{
void func(T* ptr)
{
/* Do stuff */
}
};
template <typename T, auto U = My_struct> // Here's the problem, i'd like to give the typename T to My_struct like My_struct<T>
struct Other_struct
{
// Do stuff
};
How can I do that ? Is that even possible in C++ ?
template <typename T>
struct My_struct
{
void func(T* ptr)
{
/* Do stuff */
}
};
template <typename T, typename U = My_struct<T>>
struct Other_struct
{
// Do stuff
};
You don't need auto here, use template
Is there any way to call a class member function that takes only 1 template argument instead of 2?
I would like to write some code like this:
template<typename T, size_t N>
void Container<int, N>::quick_sort() {
}
You cannot partial specialize a method, you could partial specialize the whole class, but require some duplication.
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort();
};
template <typename T,size_t N>
void Container<T, N>::quick_sort()
{
// ...
}
// Class specialization
template <size_t N>
class Container<int, N>
{
// Some similar/same code...
void quick_sort();
};
template <size_t N>
void Container<int, N>::quick_sort()
{
// ...
}
As alternative, C++17 allows
template<typename T, size_t N>
class Container
{
// Some code ...
void quick_sort()
{
if constexpr (std::is_same_v<int, T>) {
// ...
} else {
// ...
}
}
};
For prior versions, regular if would probably produces error (both branches should be valid, even if not taken).
So tag dispatching is an easy approach (SFINAE is another one):
template <typename> struct Tag{};
template<typename T, size_t N>
class Container
{
private:
void quick_sort(tag<int>)
{
// ...
}
template <typename U>
void quick_sort(tag<U>)
{
// ...
}
public:
void quick_sort()
{
quick_sort(Tag<T>());
}
// Some code ...
};
I have class like this:
template<typename T>
MyClass{
//myFunc();
}
I want to create myFunc method that return numeric value if class template is numeric and return nothing (void) when class template is not numeric.
For now, I got sth like this:
template<typename T>
MyClass{
template <typename returnT>
returnT myFunc();
}
template <typename T>
template <typename returnT>
typename std::enable_if<std::is_arithmetic<T>::value>
T MyClass<T>::myFunc()
{
return T::value;
}
template <typename T>
template <typename returnT>
typename std::enable_if<!std::is_arithmetic<T>::value>
void MyClass::myFunc()
{
//do sth
}
of course, that doesn't work. Is that a good idea to solve this problem this way? What is "smart" and working solution?
As an alternative to the constexpr if solution already supplied, here is your initial idea in it's working form.
#include <type_traits>
#include <iostream>
template<typename T>
struct MyClass{
template <typename returnT = T, std::enable_if_t<std::is_arithmetic_v<returnT>, bool> = true>
T myFunc();
template <typename returnT = T, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool> = true>
void myFunc();
};
template <typename T>
template <typename returnT, std::enable_if_t<std::is_arithmetic_v<returnT>, bool>>
T MyClass<T>::myFunc()
{
std::cout << "yo\n";
return T{};
}
template <typename T>
template <typename returnT, std::enable_if_t<!std::is_arithmetic_v<returnT>, bool>>
void MyClass<T>::myFunc()
{
std::cout << "yay\n";
}
int main() {
MyClass<int> m;
MyClass<std::string> n;
m.myFunc();
n.myFunc();
}
The simplest way I can think of would be to just use if constexpr:
template <typename T>
class MyClass
{
auto myFunc()
{
if constexpr (std::is_arithmetic_v<T>)
{
return T{};
}
else
{
// do smth
}
}
};
If you can't use C++17, you will have to revert to some SFINAE-based approach. What that would best look like exactly depends a lot on what the actual signatures involved should be. But, for example, you could provide a partial class template specialization for the case of an arithmetic type:
template <typename T, typename = void>
class MyClass
{
void myFunc()
{
// do smth
}
};
template <typename T>
class MyClass<T, std::enable_if_t<std::is_arithmetic<T>::value>>
{
T myFunc()
{
return {};
}
};
Note that an arithmetic type cannot be a class type or enum, so I'm not sure what T::value was trying to achieve in your example code for the case of T being an arithmetic type…
I would create a helper template class to select the return type, and a helper function that uses overloading to perform the right behavior.
template <typename, bool> struct RType;
template <typename T> struct RType<T, false> { typedef void type; };
template <typename T> struct RType<T, true> { typedef T type; };
template<typename T>
class MyClass{
typedef RType<T, std::is_arithmetic<T>::value> R;
void myFuncT(RType<T, false>) {}
T myFuncT(RType<T, true>) { return 0; }
public:
typename R::type myFunc() { return myFuncT(R()); }
};
By using template template parameters one can pass to a class a templated class without specifying types on its parameters. I was wondering is there a way to pass into a template template parameter a templated signature of a function to be able to specialize which variant of the function is to be considered forward.
To be clear - I know I cannot do that:
template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo)> f;
}
But somehow I would like to be able to pass templated signature of function to Foo. Is it even possible?
I couldn't believe that this is not possible so I searched a bit and found a way to do exactly what I wanted. I used templated using with a syntax:
template <template<class... Args> class FooType>
struct Foo {
FooType<int> ft;
};
template <class Res, class... Args>
using FooSignature = Res(*)(Args...);
int foo() {
return 1;
}
int main() {
Foo<FooSignature> f;
f.ft = foo;
}
This however still leaves the question how can this be possible since the standard states something opposite.
In the example below one has a template template parameter that accepts the preferred signature for the function.
Because of the specialization and the lack of a body for the template class, only types for callables are accepted.
It is a generalization of what the OP actually asked:
#include<cassert>
template<typename F>
struct S;
template<typename R, typename... Args>
struct S<R(Args...)> {
using type = R(*)(Args...);
};
template<template<typename> class F>
struct T {
typename F<void(int)>::type ft;
typename F<double(double, double)>::type gt;
};
void f(int) { }
double g(double x, double y) { return x+y; }
int main() {
T<S> t;
t.ft = f;
t.gt = g;
t.ft(42);
auto v = t.gt(1., 1.);
assert(v == 2.);
}
As can be seen in this answer
Template of function pointer is illegal in C++
The C++ Standard says in $14/1,
A template defines a family of classes or functions.
Further quoting from the linked answer:
Please note that it does NOT say "A template defines a family of classes, functions or function pointers"
However, you can pass concrete function pointers, and specialise on their signature:
#include <iostream>
template <class T>
void foo(T) { }
template <typename>
struct Foo;
template<typename T>
struct Foo<void(T)>
{
void cb() { std::cout << "T\n"; }
};
template<>
struct Foo<void(int)>
{
void cb() { std::cout << "int\n"; }
};
template<>
struct Foo<void(double)>
{
void cb() { std::cout << "double\n"; }
};
int main()
{
Foo<decltype(foo<int >)>().cb(); // outputs 'int'
Foo<decltype(foo<double>)>().cb(); // outputs 'double'
Foo<decltype(foo<char >)>().cb(); // outputs 'T'
return 0;
}
template of template is still a template.
template <class T>
void foo() { /*...*/ }
template <typename T>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo<int>)> f;
}
You cannot pass a function template as an argument. What you can do is wrap a function template in a generate lambda taking a tag parameter:
template <class T> struct tag_t { using type = T; };
template <class T>
void foo() { ... }
template <class F>
void call_func_with(F f) {
f(tag_t<int>{} );
f(tag_t<double>{} );
}
call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );
Here, f(tag_t<X>{} ) ends up calling foo<X>(), as desired.
Say I have some class template:
template<typename T>
class {
// ....
}
I can partially specialize this template for ALL pointers by:
template<typename T>
class<T *> {
// ....
}
Can I somehow specialize the template for ALL enums? i.e., do something like:
(this doesn't work, though)
template<typename T>
class<enum T> {
// ....
}
use C++11 and SFINAE.
#include <type_traits>
template<typename T, typename = void>
struct Specialize
{
};
template<typename T>
struct Specialize<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
void convert() { }
};
enum E
{
};
int main()
{
Specialize<E> spec;
spec.convert();
}
Without C++11 use boost::enable_if and boost::is_enum