How to specialize member functions based on class template argument - c++

What the question says. In addition, is it possible to do this inline?
Here is a small example just to give an idea...
template<typename T>
class Foo {
public:
Foo() :z(0.0) {}
void do( const Foo<T> &f ) {
z = f.z;
}
// specialize 'do' for Foo<int>, possible inline?
private:
T z;
};

You don't need to do anything complicated. Just use overloading and delegation. Note that we cannot just add an int overload, because when T turns out to be int too, this would be an invalid overload (two functions with the same signature)
template<typename T>
class Foo {
public:
Foo() :z(0.0) {}
void doIt(const Foo<T> &f ) {
doItImpl(f);
}
private:
template<typename U>
void doItImpl(const Foo<U> &f) {
z = f.z;
}
void doItImpl(const Foo<int> &f) {
/* ... */
}
private:
T z;
};
Or, for this case, you can do this by specialization
template<typename T>
class Foo {
public:
Foo() :z(0.0) {}
void doIt(const Foo<T> &f ) {
z = f.z;
}
private:
T z;
};
template<>
inline void Foo<int>::doIt(const Foo<int> &f) {
/* ... */
}
Using specialization this way is only possible if all template arguments are fixed. In other words, partially specializing the member function is not possible.

You can sort of get this behavior by making the member function a member function template and using SFINAE (substitution failure is not an error). For example:
template <typename U>
typename std::enable_if<!std::is_integral<U>::value &&
std::is_same<T, U>::value, void>::type
f(const Foo<U>& x)
{
}
template <typename U>
typename std::enable_if<std::is_integral<U>::value &&
std::is_same<T, U>::value, void>::type
f(const Foo<U>& x)
{
}
The is_integral type trait test whether U is an integer type. If it is not, the first is instantiated; if it is, the second is instantiated.
The is_same type trait tests to ensure T and U are the same type. This is used to ensure that the member function template is not instantiated for any type other than Foo<T>.
This example makes use of the C++0x <type_traits> library; Boost also has a type traits library that you can use, which works mostly the same.

You may try to do something like this (didn't test, might not work):
template<typename T>
class Foo {
public:
Foo() :z(0.0) {}
template<typename Ty = T>
void do( const Foo<T> &f ) {
z = f.z;
}
template<>
void do<int>( const Foo<T> &f ) {
//specialized code
}
private:
T z;
};

Related

template function overload: enable_if for CRTP, compiler insists on selecting generic function

This is a model case where there is a generic function func and then (humanely speaking) more specialized function func for classes deriving from Base via CRTP, which is only enabled for appropriate argument type via enable_if.
#include<type_traits>
#include<iostream>
// CRTP hierarchy
template<class T> class Base{ };
class Derived: public Base<Derived>{};
// overload 1
template<class T> void func(const T& a){ std::cerr<<"1\n"; }
// overload 2
template<class T, typename std::enable_if<std::is_base_of<Base<T>,T>::value,int>::type* = nullptr>
inline void func(const Base<T>& obj){ std::cerr<<"2\n"; }
int main(void){ func(Derived()); }
The compiler still thinks, however, that the first overload is a better match. I understand that enable_if only enables the function but does not make it better for the overload resolution.
I am sorry to say I was not able to make much sense from Function template section of c++ reference.
Can anyone give an advise how to make compiler prefer the second function?
Thanks!
Edit: MOTIVATION: In the real use, those functions should handle various scalar and array types (Eigen, in particular, which is using CRTP). Scalars should cover all numeric types like ints, floats, ... (without enumerating them) and the other overload should cover arrays — again, without enumerating them, but knowing all of them derive from Eigen::DenseBase<Derived>.
Just use constexpr ifs to select the correct function from a single public function.
C++17
namespace
{
template<typename T>
inline void base_func( const T& derived );
template<typename T>
inline void other_func( const T& otherType );
}
template<typename T>
inline void func( const T& type )
{
if constexpr( std::is_base_of_v<Base<T>, T> )
base_func( type );
else
other_func( type );
}
C++14 Using traits
namespace
{
template<typename T>
inline void base_func( const T& derived );
template<typename T>
inline void other_func( const T& otherType );
template <bool B>
struct func_select_trait;
template <>
struct func_select_trait<true>
{
template <typename T>
static void call( const T& derived ) { base_func<T>( derived ); }
};
template <>
struct func_select_trait<false>
{
template <typename T>
static void call( const T& otherType ) { other_func<T>( otherType ); }
};
}
template<typename T>
inline void func( const T& type )
{
func_select_trait<std::is_base_of<Base<T>, T>::value>::call<T>( type );
}
The 2 overloads are viables
overload 1. has exact match
overload 2. has derived to base conversion
See:
https://en.cppreference.com/w/cpp/language/overload_resolution#Ranking_of_implicit_conversion_sequences for more details
You might SFINAE the first overload:
// overload 1
template <class T, std::enable_if_t<!std::is_base_of_v<Base<T>, T>, int> = 0>
void func(const T& a){ std::cerr<<"1\n"; }
Demo

pointer-to-member type and template

First I got to class for this test:
struct Foo {
void test() {
std::cout << "test" << std::endl;
}
};
struct Bar {
Foo foo;
};
and a template class which accepts a pointer-to-member when constructing:
template<typename Type, typename MemberType>
class test {
public:
test(Type &t, MemberType Type::* p) : t(t) {
(t.*p).test();
}
Type &t;
};
it works well, instantiation can be done by using test<Bar, Foo> test(bar, &Bar::foo);, except that it is boring to write Bar and Foo every time since it can be deduced for &Bar::foo, so I decide to make a specialization version:
template<typename Type, typename MemberType, MemberType Type::*p>
class test<MemberType Type::*p> {
public:
test(Type &t) {
(t.*p).test();
}
};
ok, I don't really know how to do this, I just want to pass a MemberType Type::*p as the only template parameter like this: test<&Bar::foo> test(bar);
Then I create a brand new class:
template<typename Type, typename MemberType, MemberType Type::*p>
class test2 {
public:
test2(Type &t) {
(t.*p).test();
}
};
now I can pass as a template argument rather than a constructor argument, but this time I have to write three paramters:test2<Bar, Foo, &Bar::foo> test2(bar);
So what's the right way on earth that I can simply use test<&Bar::foo> test(bar);?
You almost got it correctly.
The primary template has to use an auto template parameter (a C++17 feature):
template <auto MemberPtr> class test {};
Then the specialization:
template <typename Type, typename MemberType, MemberType Type::*p>
class test<p> // Note `p` instead of `MemberType Type::*p`.
{
public:
test(Type &t)
{
(t.*p).test();
}
};
An alternative: test t(bar, &Bar::foo);
This use your primary template:
template<typename Type, typename MemberType>
class test {
public:
test(Type &t, MemberType Type::* p) : t(t) {
(t.*p).test();
}
Type &t;
};
and template argument deduction (TAD).
Live demo: https://coliru.stacked-crooked.com/a/52ee3ddba011473b
From C++17 onwards this is the exact intended use case for user defined deduction guides. Pre-C++17 one often used make functions for this.
#include <iostream>
template<typename Type, typename MemberType>
class test {
public:
test(Type &t, MemberType Type::* p) : t(t) {
(t.*p).test();
}
Type &t;
};
// C++17 user defined deduction guide
template<typename Type, typename MemberType>
test(Type &t, MemberType Type::* p) -> test<std::decay_t<decltype(t)>, decltype(static_cast<std::decay<decltype(t)>>(t).*p) >;
// pre C++17 make function
template<typename Type, typename MemberType>
test<Type, MemberType> make_test(Type &t, MemberType Type::* p) {
return test<Type, MemberType>(t, p);
}
struct Foo {
void test() {
std::cout << "test" << std::endl;
}
};
struct Bar {
Foo foo;
};
int main() {
Bar b;
test<Bar, Foo> t1 (b, &Bar::foo);
// Only works in C++17
test t2(b, &Bar::foo);
auto t3 = make_test(b, &Bar::foo);
}

Templates from double parametres [duplicate]

The following code:
template <typename S, typename T>
struct foo {
void bar();
};
template <typename T>
void foo <int, T>::bar() {
}
gives me the error
invalid use of incomplete type 'struct foo<int, T>'
declaration of 'struct foo<int, T>'
(I'm using gcc.) Is my syntax for partial specialization wrong? Note that if I remove the second argument:
template <typename S>
struct foo {
void bar();
};
template <>
void foo <int>::bar() {
}
then it compiles correctly.
You can't partially specialize a function. If you wish to do so on a member function, you must partially specialize the entire template (yes, it's irritating). On a large templated class, to partially specialize a function, you would need a workaround. Perhaps a templated member struct (e.g. template <typename U = T> struct Nested) would work. Or else you can try deriving from another template that partially specializes (works if you use the this->member notation, otherwise you will encounter compiler errors).
Although coppro mentioned two solutions already and Anonymous explained the second one, it took me quite some time to understand the first one. Maybe the following code is helpful for someone stumbling across this site, which still ranks high in google, like me. The example (passing a vector/array/single element of numericalT as dataT and then accessing it via [] or directly) is of course somewhat contrived, but should illustrate how you actually can come very close to partially specializing a member function by wrapping it in a partially specialized class.
/* The following circumvents the impossible partial specialization of
a member function
actualClass<dataT,numericalT,1>::access
as well as the non-nonsensical full specialisation of the possibly
very big actualClass. */
//helper:
template <typename dataT, typename numericalT, unsigned int dataDim>
class specialised{
public:
numericalT& access(dataT& x, const unsigned int index){return x[index];}
};
//partial specialisation:
template <typename dataT, typename numericalT>
class specialised<dataT,numericalT,1>{
public:
numericalT& access(dataT& x, const unsigned int index){return x;}
};
//your actual class:
template <typename dataT, typename numericalT, unsigned int dataDim>
class actualClass{
private:
dataT x;
specialised<dataT,numericalT,dataDim> accessor;
public:
//... for(int i=0;i<dataDim;++i) ...accessor.access(x,i) ...
};
If you need to partially specialise a constructor, you might try something like:
template <class T, int N>
struct thingBase
{
//Data members and other stuff.
};
template <class T, int N> struct thing : thingBase<T, N> {};
template <class T> struct thing<T, 42> : thingBase<T, 42>
{
thing(T * param1, wchar_t * param2)
{
//Special construction if N equals 42.
}
};
Note: this was anonymised from something I'm working on. You can also use this when you have a template class with lots and lots of members and you just want to add a function.
If you're reading this question then you might like to be reminded that although you can't partially specialise methods you can add a non-templated overload, which will be called in preference to the templated function. i.e.
struct A
{
template<typename T>
bool foo(T arg) { return true; }
bool foo(int arg) { return false; }
void bar()
{
bool test = foo(7); // Returns false
}
};
In C++ 17, I use "if constexpr" to avoid specialize (and rewrite) my method. For example :
template <size_t TSize>
struct A
{
void recursiveMethod();
};
template <size_t TSize>
void A<TSize>::recursiveMethod()
{
if constexpr (TSize == 1)
{
//[...] imple without subA
}
else
{
A<TSize - 1> subA;
//[...] imple
}
}
That avoid to specialize A<1>::recursiveMethod().
You can also use this method for type like this example :
template <typename T>
struct A
{
void foo();
};
template <typename T>
void A<T>::foo()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "arithmetic" << std::endl;
}
else
{
std::cout << "other" << std::endl;
}
}
int main()
{
A<char*> a;
a.foo();
A<int> b;
b.foo();
}
output :
other
arithmetic

Is there a way to SFINAE based on available overloads in the current class?

I've been using code like this for a while (since GCC 4.9/Clang 3.5 at least):
#include <utility>
class foo
{
public:
void bar(int n);
template <typename R,
typename = decltype(std::declval<foo>().bar(*std::begin(std::declval<R>())))>
void bar(const R& range);
};
The point of the second bar() overload is it should be SFINAE'd away unless R is a range type where an overload of bar() exists for its elements. So std::vector<int> would be fine but std::vector<int*> wouldn't, for example.
Unfortunately, since Clang 3.9, that gives this error:
templ.cpp:12:54: error: member access into incomplete type 'foo'
typename = decltype(std::declval<foo>().bar(*std::begin(std::declval<R>())))>
^
templ.cpp:6:7: note: definition of 'foo' is not complete until the closing '}'
class foo
^
1 error generated.
Is there a way to accomplish this that doesn't rely on using an incomplete type from within its own definition?
Maybe you could make foo a default value of additional template parameter:
#include <utility>
class foo
{
public:
void bar(int n);
template <typename R,
typename F = foo,
typename = decltype(std::declval<F>().bar(*std::begin(std::declval<R>())))>
void bar(const R& range);
};
[live demo]
This would delay the check if foo is complete.
The fast and easy way would be to define bar in a base class.
#include <utility>
template<typename child>
struct base {
void bar(int);
};
struct foo : base<foo> {
template<typename R,
typename = decltype(std::declval<base<foo>>().bar(std::begin(std::declval<R>())))>
void bar(const R& range);
};
But this method can be cumbersome.
Alternatively, if you know what type bar need, you can do this:
struct foo {
void bar(int);
template<typename R,
std::enable_if_t<std::is_constructible<int, decltype(*std::begin(std::declval<R>()))>>* = 0>
void bar(const R& range);
};
If bar is limited with a constraint, you could use the very same constraint:
struct foo {
template<typename T, std::enable_if_t<some_contraint<T>::value>* = 0>
void bar(T);
template<typename R,
std::enable_if_t<some_contraint<*std::begin(std::declval<R>())>::value>* = 0>
void bar(const R& range);
};
At last, if you like the last two options, you can encapsulate the range constraint in a type trait:
template<typename, typename = void>
struct is_valid_range : std::false_type {};
template<typename T>
struct is_valid_range<T, std::enable_if_t<some_contraint<*std::begin(std::declval<R>())>::value>> : std::true_type {};
It looks like you're trying to make it so that the overload would not be selected if the function's body wouldn't compile. The trouble is that the compiler needs to make sure that the signature compiles before moving on to the body.
Instead, how about SFINAE'ing based on what you need to be able to do with R more specifically? For example:
template<typename R,
class = decltype(begin(std::declval<const R&>())),
class = decltype(end(std::declval<const R&>()))>
void bar(const R& range);
That way this overload is only selected if you can call begin and end on a type f const R&.
class Foo;
void free_bar(Foo* foo, int n){
(void)foo;
std::cout << n << "\n";
}
class Foo {
public:
template<class X>
void bar(X&& x) {
return free_bar( this, std::forward<X>(x) );
}
};
template <typename R>
auto free_bar(Foo* foo, const R& range)
-> decltype( free_bar( foo, *std::begin(range) ) )
{
for (auto&&x:range)
free_bar(foo, decltype(x)(x));
}
This places the bar into free functions that take a Foo* as their first argument.
The member .bar(X) invokes this free function.
ADL means that it does the right thing(tm) usually.
live example

How can one determine the return type of a function at template instantiation time?

Is there a way to find out what the return type of a function (or even better of a function pointer) is ?
I've got the following code, which breaks when I use a void function pointer, but works fine for any other return type. The error I get when using a void function pointer from gcc 4.5 is:
error: void value not ignored as it ought to be
Which makes sense. So obviously I need to check if function pointer returns something, and then obtain the result and return it.
template <class F,typename R> class Instruction
{
protected:
F (func);
R result;
public:
template <typename T>
Instruction(T const& f)
{
func = &f;
};
template <typename A> void execute(A const& a)
{
result = (func)(a);
};
template <typename A> void execute(A const& a,A const& b)
{
result = (func)(a,b);
};
template <typename A> void execute(A const& a,A const& b,A const& c)
{
result = (func)(a,b,c);
};
R get_result()
{
return result;
};
};
Normally I use a function pointer to a function which does something mostly arithmetic and I can take care of any return type at instantiation other than void functions. I've tried instantiating as:
Instruction<ptr2func2,void> foo(bar);
Instruction<ptr2func2,(*void)> foo(bar);
but in both cases it fails.
The second template argument at instantiation is used in order to define what the return type will be.
Try a template partial specialization on void:
template <class F> class Instruction<F, void>
{
protected:
F (func);
public:
template <typename T>
Instruction(T const& f)
{
func = &f;
};
template <typename A> void execute(A const& a)
{
(func)(a);
};
template <typename A> void execute(A const& a,A const& b)
{
(func)(a,b);
};
template <typename A> void execute(A const& a,A const& b,A const& c)
{
(func)(a,b,c);
};
};
You may want to use Boost::FunctionTypes which provide a metafunction able to decompose function type and give you access to the return or argument type.
In C++0x you can decltype. However, in C++03, by convention, function objects have a result_type typedef, and function pointers can have template deduction applied to them.