specialize template function for template class - c++

I have an indexer function, and was attempting to specialize it for the standard container types, but get errors. I'm sure it's either simple or impossible, but I can't recall which. I would prefer these as a function-object, but I wasn't able to make that work either. Is it possible to specialize a template function for a template class
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
//others are here too, but all have the same issue
}
//default indexer
template <class T>
double indexer(const T& b) { //this seems to work fine
return b.getIndex();
}
// base types
template<> double indexer<char>(const char& b) { return double(b); }
//other primitives are here too, and work fine
// standard library
template<class T, class A>
double indexer<std::vector<T,A>>(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); } //line with error
error message:
error C2768: 'indexer' : illegal use of explicit template arguments
I would like for this to be specialization vs overloading, because I have a function A that takes a function object/pointer template parameter, and overloaded function A that calls the first A with a defaulted indexer.
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>);} //default wrapper
It seems highly likely this is a duplicate question, but I cannot seem to find one.

You cannot partially specialize template functions, only template classes.
use overloading instead:
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
//default indexer
template <class T>
double indexer(const T& b) { return b.getIndex(); }
double indexer(const char& b) { return double(b); }
template<class T, class A>
double indexer(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); }

Since functions cannot be partially specialized, I can replace the indexer functions with function objects. This seems to work fine, and solves all my problems.
namespace std { //declarations of predefined indexable types
template <class T, class A> class vector;
}
template <class T>
struct indexer {
double operator()(const T& b) const
{ return b.getIndex(); }
};
template<> struct indexer<char> {
double operator()(const char& b) const
{ return double(b); }
};
template<class T, class A> struct indexer<std::vector<T,A>> {
double operator()(const std::vector<T,A>& b) const
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
};
template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>());} //default wrapper

Here's a solution based solely on overloads, using C++11-style variadic templates:
template <typename T>
T print(const T & t)
{
std::cout << t << std::endl;
return t;
}
template <template <typename...> class Container, typename ...Args>
typename Container<Args...>::value_type print(const Container<Args...> & v)
{
typedef typename Container<Args...>::value_type T;
if (v.empty()) std::cout << "nil" << std::endl;
else std::cout << *v.begin() << std::endl;
return v.empty() ? T() : *v.begin();
}
If you want to be fancy and if you have access to an is_container type trait (e.g. taken from the pretty printer), you can make the container overload specific to containers, using enable_if:
template <template <typename...> class Container, typename ...Args>
typename std::enable_if<is_container<Container<Args...>>::value,
typename Container<Args...>::value_type>::type
print(const Container<Args...> & v)
{
/* ... */
}

Related

Specialization of function template without changing its prototype

Suppose A is some class and I have the following function template with a nontype argument:
template <typename T, int v> void func(const T& x);
Now I wish to have different implementations for different types T e.g. I want to have a general version of func for general types (general means types that do not have a special version of func designed for it) and a special version of func for class A which is different from the general version. Also, the users of this design call func in the following way:
func<int,9>(11);
func<A,1>(a); //a is an object of class A
My question is, given that function templates are not allowed to be partially specialized and overloading func would not allow users to call it in the way of func<A,1>, how am I able to correctly implement func?
Just let the type system do the work for you:
#include <iostream>
class A {};
// Default implementation
template <typename T, int v> void func(const T& x)
{
std::cout << x + v << "\n";
}
// Specialized for A
template <typename T, int v> void func(const A& x) //<-- matches A for argument T
{
std::cout << "Groovy " << v << "\n";
}
int main()
{
func<int, 9>(11);
func<double, 3>(0.14159);
func<const char*, 3>("uh oh!");
func<A, 1>(A());
}
Output:
20
3.14159
oh!
Groovy 1
Live example here
You can use C++20 concepts to do this:
#include <concepts>
struct A {};
template <typename T, int v>
void func(const T& x) {
// general version
}
template <std::same_as<A> T, int v>
void func(const T& x) {
// special version
}
Demo.
With C++11, you can use std::enable_if to do what you want as follows:
#include <iostream>
class A
{
};
template <typename T, int v> void func(const T&) //primary template
{
std::cout<<"primary template"<<std::endl;
}
template <typename T, typename std::enable_if<std::is_same<T, A>::value, int>::type v>
void func(const A&)
{
std::cout<<"choosen for A"<<std::endl;
std::cout<<v<<std::endl;
}
int main()
{
A a;
func<int, 9>(11);
func<A, 9>(a);
}
Thanks to #Jarod42 for correcting me.(see the comments below and edit history of this post)
If you just want to handle A and doesn't need a customization point,
since C++17, you might use if conxtexpr:
template <typename T, int v>
void func(const T& x)
{
if constexpr (std::is_same_v<T, A>) {
// specific code for A
} else {
// generic code: Not a A
}
}
Else, you may delegate implementation to other functors/functions that you can customize:
template <typename T, int v>
struct func_impl
{
void operator()(const T&) const { /* Generic code */ }
};
template <typename T, int v> void func(const T& x)
{
func_impl<T, v>{}(x);
}
// Customization part
class A;
template <int v>
struct func_impl<A, v>
{
void operator()(const A&) const { /* Specific code for A */ }
};
or
// Allow both parameters to be deducible, to ease the possibility to overload
// on any part.
template <typename T, int v>
void func_impl(std::integral_constant<int, v>, const T& x)
{
// Generic code
}
template <typename T, int v> void func(const T& x)
{
func_impl(std::integral_constant<int, v>{}, x);
}
// Customization point (with ADL)
class A;
template <int v>
void func_impl(std::integral_constant<int, v>, const A& x)
{
// Specific code for A.
}

Double `template` keyword in static member definition

I was not using the latest C++ standard for a while, today I want to implement a Haskell style List in C++ and come up with something like the following:
template<typename T>
class List {
private:
std::function<std::tuple<T,List<T>>()> f;
List() {}
List(T h, List<T> t) :f([h, t]() { return std::make_tuple(h, t); }) {}
public:
typedef T item_type;
static List<T> empty();
static List<T> cons(T h, List<T> t);
template<typename N, typename C>
static auto on(N n, C c) -> decltype(N());
};
template<typename T>
List<T> List<T>::empty() {
return List();
}
template<typename T>
List<T> List<T>::cons(T h, List<T> t) {
return List([h, t](std::function<void(T, List<T>)> c) {f(c); });
}
template<typename T>
template<typename N, typename C>
auto List<T>::on(N n, C c) -> decltype(N()) {
if (f == nullptr) return n();
else {
T h;
List<T> t;
std::tie(h, t) = f();
return c(h, t);
}
}
template<typename T, typename R, typename F>
R foldr(List<T> l, F f, R b) {
return l.on([b]() { return b; }, [f, b](T h, List<T> t) { return foldr(t, f, f(t, b)); });
}
The code compiles (VC 2015, not tested yet), but makes me a while to figure out the correct grammar for the function on. This is the first time I saw something like this in C++, and the double template keyword looks strange enough to me.
Question
Is this the normal way when we declare static generic methods that uses template variable not available through the class template? Can anyone point me out some clauses in the standard?
Is this the normal way when we declare static generic methods that
uses template variable not available through the class template?
Yes, it is normal.
Can anyone point me out some clauses in the standard?
From the n4296, 14.5.2 Member templates:
A template can be declared within a class or class template; such a
template is called a member template. A member template can be defined
within or outside its class definition or class template definition. A
member template of a class template that is defined outside of its
class template definition shall be specified with the
template-parameters of the class template followed by the
template-parameters of the member template. [ Example:
template<class T> struct string {
template<class T2> int compare(const T2&);
template<class T2> string(const string<T2>& s) { / ... / }
};
template<class T> template<class T2> int string<T>::compare(const T2& s) {
}
—end example ]

Avoiding compiling certain lines based on template operator existence

I'm currently creating a template container class in which I like to have a sorting ability whenever the template class has the comparison operator.
With SFINAE I can determine if the operator exist during runtime. However, when compiling the code below it of course still tries to compile the line containing sort, which will return compiler errors if the compare operator is not specified for that class.
Is there a way to 'avoid' compiling that line if the comparison operator doesn't exist? Not knowing the naming of such procedure, something like an '#ifdef SFINAE'?
template <class UseClass> class Container {
public:
bool Sort(void) {
if (CHECK::opCompareExists<UseClass>::value) {
sort(m_classlist.begin(),m_classlist.end()); //compile error, of course
return true;
}
return false;
}
private:
vector<UseClass> m_classlist;
};
Maybe I shouldn't use SFINAE at all... maybe it should be a template specification? How would that work (based on automatic detection that the operator is not present)?
std::sort() by default uses the less-than operator (operator<()) to compare elements so you can simply use expression SFINAE to rule out a specific overload if the type doesn't have it:
template<typename T = UseClass>
auto Sort() -> decltype(std::declval<T>() < std::declval<T>(), bool())
{
return true;
}
If substitution fails (SomeClass does not have operator<()) then compilation will fail.
If this wasn't your intention, and instead you wanted to return true if it could sort and false otherwise, then you need a trait class that you can overload based on:
namespace detail
{
template<typename T>
auto has_less_than_impl(int)
-> decltype(std::declval<T>() < std::declval<T>(), std::true_type());
template<typename>
std::false_type has_less_than_impl(...);
}
template<typename T>
struct has_less_than : decltype(detail::has_less_than_impl<T>(0)) { };
template <class UseClass> class Container
{
public:
bool Sort() { return Sort(has_less_than<UseClass>::value); }
private:
bool Sort(std::true_type)
{
sort(m_classlist.begin(), m_classlist.end());
return true;
}
bool Sort(std::false_type) { return false; }
};
Update: As per your comment here is a C++03 implementation:
template <typename T>
class has_less_than {
struct Fallback { bool operator<(T const&); };
struct Derived : T, Fallback {};
template <typename U, U> struct S;
template <typename C> static char (&f(S<bool (Fallback::*)(T const&), &C::operator<>*))[1];
template <typename C> static char (&f(...))[2];
public:
const static bool value = sizeof(f<Derived>(0)) == 2;
};
namespace detail
{
template <bool B, typename R = void>
struct enable_if { typedef R type; };
template <typename R>
struct enable_if<false, R> { };
}
template <class UseClass> class Container {
public:
bool Sort() { return Sort<UseClass>(); }
private:
template <typename T>
bool Sort(typename detail::enable_if<has_less_than<T>::value, int>::type = 0) {
sort(m_classlist.begin(),m_classlist.end());
return true;
}
template <typename T>
bool Sort(typename detail::enable_if<!has_less_than<T>::value, int>::type = 0) {
return false;
}
private:
vector<UseClass> m_classlist;
};

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.

C++ template partial specialization question

I'm having compile time trouble with the following code:
template <typename T,
template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b);
template <typename T, std::vector> // HERE
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
...
vector<int> a, b;
cout << is_in(a,b) << endl;
The error message is (on the line marked "HERE"):
error: 'std::vector' is not a type
(of course, I have included vector from std!). Any suggestion? I fiddled with it for a while, but I'm getting to the point where I could use some help :-) I need to partially specialize the initial template declaration so that I can have the compiler switch implementations depending on the actual type of the container C (there will be a is_in for sets, one for vectors, one for ranges..., with different algorithms each time).
Thanks!
The partial specialization of a function template is not allowed by the Standard.
A simple solution is : use overload.
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
This is overloaded function template. Its NOT partial specialization.
Or, you could do this:
namespace detail
{
template<typename T, typename C>
struct S
{
static bool impl(const C & a, const C & b)
{
//primary template
//...
}
}
template<typename T>
struct S<T, std::vector<T> >
{
static bool impl(const std::vector<T> & a, const std::vector<T> & b)
{
//partial specialization for std::vector
return false;
}
}
}
template <typename T, template <class T, class Allocator = std::allocator<T> > class C>
bool is_in(const C<T>& a, const C<T>& b)
{
return detail::S<T, C<T> >::impl(a,b);
}
Function template partial specialization is not allowed. In any case you're not using the template specialization syntax, you're actually writing an additional overload. Try this instead:
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
return false; // implementation tbd
}
If partial specialization were allowed, it would look like this instead:
template <typename T> // std::vector is not a template parameter,
// so we wouldn't put it here
bool is_in<T, std::vector>(const std::vector<T>& a, const std::vector<T>& b)
// instead, it'd appear ^ here, when we're specializing the base template
{
return false; // implementation tbd
}
I don't know if it works (as template templates are always a trouble to my mind), but what about just trying
template <typename T>
bool is_in(const std::vector<T>& a, const std::vector<T>& b)
{
...
}
as it's a specialization.
EDIT: Others have clarified on this already, but I'll add it for completeness. The above code is actually an overload and not a partial specialization, but partial function specializations aren't allowed anyway.