operator() template specialization - c++

I'm trying to do specialization to template operator, the template looks like this:
template <typename Iterator1, typename Iterator2>
ResultType operator()(Iterator1 a, Iterator2 b, size_t size, ResultType worst_dist = -1) const
after i did the specialization that looks like this:
template <>
float operator()<float*,float*>(float* a, float const* b, unsigned long size, float worst_dist = -1) const
i get an error during compilation :
Cannot specialize a function 'operator()' within class scope
All those function are in struct template
I'll be glad to get some help.
thanks.

Why do you want to specialize this operator anyway? You won't be able to call it using the syntax which depends on specializations (i.e. explicit providing the [some of] the template arguments) anyway! Just use overloading and you should be fine. Although it is sometimes desirable or even necessary to use the notation where you explicitly specify the template arguments, it tends to be not that important for functions in general to use specialization rather than overloading.
I just read things up in the standard and actually is possible to provide an explicit specialization, however it has to be outside of the class definition. For example:
#include <iostream>
struct foo
{
template <typename T> void operator()(T const&) {
std::cout << "general\n";
}
};
template <>
void foo::operator()<int>(int const&) {
std::cout << "int spec\n";
}
int main()
{
foo f;
f(1.2);
f(1);
f<double>(1); // <-- ERROR: doesn't work!
}
This would have worked the same using overloading. Using explicitly specified template arguments still doesn't work, though.

Related

Why do we need 'template <class T>' before implementing all templated class methods

If we have a standard class:
class Foo {
public:
int fooVar = 10;
int getFooVar();
}
The implementation for getFooVar() would be:
int Foo::getFooVar() {
return fooVar;
}
But in a templated class:
template <class T>
class Bar {
public:
int barVar = 10;
int getBarVar();
}
The implementation for getBarVar() must be:
template <class T>
int Bar<T>::getBarVar(){
return barVar();
}
Why must we have the template <class T> line before the function implementation of getBarVar and Bar<T>:: (as opposed to just Bar::), considering the fact that the function doesn't use any templated variables?
You need it because Bar is not a class, it's a template. Bar<T> is the class.
Bar itself is a template, as the other answers said.
But let's now assume that you don't need it, after all, you specified this, and I added another template argument:
template<typename T1, typename T2>
class Bar
{
void something();
};
Why:
template<typename T1, typename T2>
void Bar<T1, T2>::something(){}
And not:
void Bar::something(){}
What would happen if you wanted to specialize your implementation for one type T1, but not the other one? You would need to add that information. And that's where this template declaration comes into play and why you also need it for the general implementation (IMHO).
template<typename T>
void Bar<T, int>::something(){}
When you instantiate the class, the compiler checks if implementations are there. But at the time you write the code, the final type (i.e. the instantiated type) is not known.
Hence the compiler instantiates the definitions for you, and if the compiler should instantiate something it needs to be templated.
Any answer to this question boils down to "because the standard says so". However, instead of reciting standardese, let's examine what else is forbidden (because the errors help us understand what the language expects). The "single template" case is exhausted pretty quickly, so let's consider the following:
template<class T>
class A
{
template<class X>
void foo(X);
};
Maybe we can use a single template argument for both?
template<class U>
void A<U>::foo(U u)
{
return;
}
error: out-of-line definition of 'foo' does not match any declaration in 'A<T>'
No, we cannot. Well, maybe like this?
template<class U>
void A<U>::foo<U>(U u)
{
return;
}
error: cannot specialize a member of an unspecialized template
No. And this?
template<class U, class V>
void A<U>::foo(V u)
{
return;
}
error: too many template parameters in template redeclaration
How about using a default to emulate the matching?
template<class U>
template<class V = U>
void A<U>::foo(V u)
{
return;
}
error: cannot add a default template argument to the definition of a member of a class template
Clearly, the compiler is worried about matching the declaration. That's because the compiler doesn't match template definitions to specific calls (as one might be used to from a functional language) but to the template declaration. (Code so far here).
So on a basic level, the answer is "because the template definition must match the template declaration". This still leaves open the question "why can we not just omit the class template parameters then?" (as far as I can tell no ambiguity for the template can exist so repeating the template parameters does not help) though...
Consider a function template declaration
tempalte <typename T>
void foo();
now a definition
void foo() { std::cout << "Hello World"; }
is either a specialization of the above template or an overload. You have to pick either of the two. For example
#include <iostream>
template <typename T>
void foo();
void foo() { std::cout << "overload\n"; }
template <typename T>
void foo() { std::cout << "specialization\n"; }
int main() {
foo();
foo<int>();
}
Prints:
overload
specialization
The short answer to your question is: Thats how the rules are, though if you could ommit the template <typename T> from a definition of the template, a different way would be required to define an overload.

explicit specialization of a function template (which is a member of a class template) produces "partial specialization is not allowed" error, why?

I am working on Visual Studio 2015 community edition
let's say I have, a simple class like this:
(The example below "should be" a compilable because it include all the necessary stuff, unfortunately, it produces an error).
#include <stdexcept>
template <typename T>
class class_foo
{
// members, methods, constructors. not important stuff...
// helper functions:
private:
class tag_aaa {}; // to resolve few things at compile-time, not run-time.
class tag_bbb {}; // - || -
template <typename tag>
void erase();
// for some reason this is not interpreted as an error by my compiler:
template<>
void erase<tag_aaa>();
template<>
void erase<tag_bbb>();
};
// catch-all-do-nothing "version"
// well, catch-all-throw-an-exception because call to this function is an obvious error.
// that should never occur.
template <typename T>
template <typename tag> inline
void class_foo<T>::erase()
{
throw std::runtime_error("Very weird error...");
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_aaa>()
{
// do some stuff...
}
template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_bbb>()
{
// do some stuff...
}
int main()
{
class_foo<double> bar;
return 0;
}
The error:
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(36): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_aaa> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(43): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_bbb> [with T=T]" is not allowed
1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(51): warning : variable "bar" was declared but never referenced
I think about myself as a junior-hobbyist programmer, so certainly I am wrong, but I believe that both erase<class_foo<T>::tag_aaa>() and erase<class_foo<T>::tag_bbb>() are explicit specializations of the template <typename tag> void erase(); function. And as such, they are allowed. I believe that this error is due to some bad syntax but I can't find an error.
Question:
Is what I am trying to do, allowed?
If yes, what am I doing wrong?
If yes, what is the correct syntax for specializing this functions (erase)?
It look like full specialization of a template function but it's still partial specialization, hence the compilation error.
Why is it? Well, look at this specialization:
template <>
template <typename T>
inline void class_foo<T>::erase<class_foo<T>::tag_bbb>() {
// do some stuff...
}
You said it's a explicit specialization, but there is still a template parameter to fill! There's the parameter T yet to be known. So a specialization... that is still a template? That's a partial specialization!
Partial specialization of function is not allowed, for many reason. One of them is that it won't play nicely with overloading.
To effectively specialize the function, you must leave no template parameter to be known, something like this:
template<>
template<>
inline void class_foo<int>::erase<class_foo<int>::tag_bbb>() {
// do some stuff...
}
But it's not what you want.
Here's how I'd fix this problem. Use overloading instead of specializing:
template<typename T>
struct class_foo {
private:
struct tag_aaa {};
struct tag_bbb {};
void erase(tag_aaa) {
// Stuff when tag_aaa
}
void erase(tag_bbb) {
// Stuff when tag_bbb
}
};
Instead of invoking those like this:
erase<tag_aaa>(); // with specialization
You must invoke it like that:
erase(tag_aaa{}); // with overloading

C++ std::function-like template syntax

In C++11 you can instantiate std::function like this:
std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on
But while there is plenty of info on variadic templates on the web, I fail to find any articles on how to write std::function-like template which would accept parenthesized arguments.
Could anyone please explain the syntax and its limitations or at least point to an existing explanation?
There's nothing special about it, it's an ordinary function type. When you declare a function like this:
int foo(char a, double b)
Then its type is int (char, double). One way of "unwrapping" the individual argument types and return type is to use partial template specialisation. Basically, std::function looks something like this:
template <class T>
struct function; // not defined
template <class R, class... A>
struct function<R (A...)>
{
// definition here
};
Pretty much like any other template, since int(std::string, std::string) is just a type.
Here's a really naive example that compiles:
template <typename FType>
struct Functor
{
Functor(FType* fptr) : fptr(fptr) {}
template <typename ...Args>
void call(Args... args)
{
fptr(args...);
}
private:
FType* fptr;
};
void foo(int x, char y, bool z) {}
int main()
{
Functor<void(int, char, bool)> f(&foo);
f.call(1, 'a', true);
//f.call(); // error: too few arguments to function
}
In reality you'd have a specialisation on FType being ReturnType(ArgTypes...), though my naive example will already give you the validation you need if you try to invoke it in in compatible ways.

select method code depending on template value

I've got a template c++ object as follows
template <typename T, Dimension D>
class Field : public std::vector<T>
{
// ... lot of stuff ...
T differentiate(const gridPoint<D>&, int) const;
};
This differentiate methode is computed differently depending of the Dimension D
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
I could just put a switch inside the method's body bt I'd like to use the templates in order to help with clarity
I tried using std::enable_if like this:
template <typename T, Dimension D>
typename std::enable_if<D==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... lot of computation
}
template <typename T, Dimension D>
typename std::enable_if<D==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... even more computation
}
but the compiler tels me that my implementation doesn't match any prototypes
What did I do wrong ? I just can't figure out how i'm suppose to declare the method's code
You can probably save yourself a lot of hassle and unreadable code in the long run by writing distinct partial specializations of Field for the 2D and 3D case:
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
using gridPoint = std::array<int, D>;
template <typename T>
struct Field_base : std::vector<T> {
// Stuff common to both specializations goes here.
using std::vector<T>::vector;
};
template <typename, Dimension>
struct Field;
template <typename T>
struct Field<T, _2D> : Field_base<T>
{
using grid_point = gridPoint<_2D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "2D differentiate called\n";
return {};
}
};
template <typename T>
struct Field<T, _3D> : Field_base<T>
{
using grid_point = gridPoint<_3D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "3D differentiate called\n";
return {};
}
};
For SFINAE to work, I believe the function needs to be templated so that this becomes a choice of which function compiles during overload resolution, not which function compiles during class instantiation.
I modified this as follows and it "works" on this end:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
struct gridPoint
{
int d[D];
};
template <typename T, Dimension D>
struct Field : public std::vector<T>
{
template <Dimension D2>
typename std::enable_if<D== D2 && D==_2D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "2D differentiate called" << std::endl;
return T(0.0);
}
template <Dimension D2>
typename std::enable_if<D==D2 && D==_3D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "3D differentiate called" << std::endl;
return T(0.0);
}
};
int main() {
Field<double, _2D> foo;
gridPoint<_2D> point { 3, 4 };
foo.differentiate(point, 3);
gridPoint<_3D> p3 { 3, 4, 5 };
Field<double, _3D> bar;
bar.differentiate(p3, 8);
return 0;
}
I didn't sort out the template foo to get this to compile with the definition out-of-line.
The compiler error provoked by your attempted out-of-line SFINAE definitions
for T Field<T,Dimension>::differentiate(const gridPoint<D>&, int) const would be:
error: prototype for ‘typename std::enable_if<(D == _2D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
error: prototype for ‘typename std::enable_if<(D == _3D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
or words to that effect.
The compiler insists that any purported out-of-line definition of a member function
of Field<T,Dimension> has the same prototype as the declaration of
of some member function, and its diagnostics spell out that this requirement is
not satisfied for either of the purported out-of-line definitions.
It is no good protesting that if the compiler would just carry on and do the SFINAE,
it then would discover that the one surviving out-of-line definition matches a member function declaration. It can't do
the SFINAE until it attempts some instantiation of Field<D,Dimension>, and making sure that
any out-of-line template/class member definitions pair off with template/class member declarations comes earlier on its
to-do list than instantiating templates. Instantiation might never happen, but orphan
member definitions are always wrong.
So, both of those SFINAE-embellished prototypes would have to appear as member
function declarations.
But then, if the compiler is to tolerate both of these SFINAE-embellished member
function declarations, they must be template member functions (not merely
member functions of a class template) and their respective std::enable_if conditions
must depend upon a template parameter of the member function. Such are the SFINAE
rules.
Summing up, what you need to write to accomplish your out-of-line SFINAE definitions is
illustrated by the following program:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template<Dimension D>
struct gridPoint {}; // ...whatever
template <typename T, Dimension D>
class Field : public std::vector<T>
{
public:
template <Dimension Dim = D>
typename std::enable_if<Dim ==_2D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
template <Dimension Dim = D>
typename std::enable_if<Dim ==_3D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
};
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_2D differentiate" << std::endl;
return T(); // ...whatever
}
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_3D differentiate" << std::endl;
return T(); // ...whatever
}
int main()
{
Field<int,_2D> f_2d;
gridPoint<_2D> gp_2d;
f_2d.differentiate(gp_2d,2);
Field<float,_3D> f_3d;
gridPoint<_3D> gp_3d;
f_3d.differentiate(gp_3d,3);
f_3d.differentiate(gp_2d,2);
return 0;
}
In this not very pleasant light, you might possibly want to review the question of whether Dimension needs to be a template parameter of
Field, or whether it might just be a template parameter of member functions of Field. As I
don't know the complete implementation of the template, I can't say. Alternatively, you might reconsider your dislike of the
template base class + partial specialization approach suggested by #casey.
Presumably you would like the alternative definitions of differentiate out-of-line because they are big and you don't want them
sprawling in the body of the class template. In thorny cases like this a plodding but fairly failsafe way of extruding template/class member definitions to be out-of-line
is first to code the template/class with inline definitions and get a successful build; then copy-paste the inline definitions to their
out-of-line places, add the required template/class qualifications and delete default specifiers; then truncate the original in-line definitions to declarations;
then get a successful build again.
The output of that example program is:
_2D differentiate
_3D differentiate
_2D differentiate
The last line is emitted by the execution f_3d.differentiate(gp_2d,2), which draws attention to the fact that the selected implementation of differentiate
is determined by the Dimension of the gridPoint<Dimension>& argument that is passed to it and not by the Dimension of the
Field<T,Dimension> on which it is invoked. Thus we can call Field<T,_3D>::differentiate<_2D>. Since you said:
This differentiate methode is computed differently depending of the Dimension D
this on the face of it seems to be the behaviour you want, as the gridPoint<Dimension>
argument differentiates the implementations of differentiate according to the value of
Dimension. But this observation revives the question: Is there really a good reason for
Dimension to be a template parameter of Field, and not just a template parameter of differentiate?
If there is really a good reason, then you want it to be impossible to call Field<T,_3D>::differentiate<_2D>
or Field<T,_2D>::differentiate<_3D>. You can achieve that by replacing all occurrences of <Dim> with
<D> in the program, though the SFINAE implementation then looks even more laboured.

Specializing single method in a big template class

In C++ if you want to partially specialize a single method in a template class you have to specialize the whole class (as stated for example in Template specialization of a single method from templated class with multiple template parameters)
This however becomes tiresome in bigger template classes with multiple template parameters, when each of them influences a single function. With N parameters you need to specialize the class 2^N times!
However, with the C++11 I think there might a more elegant solution, but I am not sure how to approach it. Perhaps somehow with enable_if? Any ideas?
In addition to the inheritance-based solution proposed by Torsten, you could use std::enable_if and default function template parameters to enable/disable certain specializations of the function.
For example:
template<typename T>
struct comparer
{
template<typename U = T ,
typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return /* floating-point precision aware comparison */;
}
template<typename U = T ,
typename std::enable_if<!std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return lhs == rhs;
}
};
We take advantage of SFINAE to disable/enable the different "specializations" of the function depending on the template parameter. Because SFINAE can only depend on function parameters, not class parameters, we need an optional template parameter for the function, which takes the parameter of the class.
I prefer this solution over the inheritance based because:
It requires less typing. Less typing probably leads to less errors.
All specializations are written inside the class. This way to write the specializations holds all of the specializations inside the original class , and make the specializations look like function overloads, instead of tricky template based code.
But with compilers which have not implemented optional function template parameters (Like MSVC in VS2012) this solution does not work, and you should use the inheritance-based solution.
EDIT: You could ride over the non-implemented-default-function-template-parameters wrapping the template function with other function which delegates the work:
template<typename T>
struct foo
{
private:
template<typename U>
void f()
{
...
}
public:
void g()
{
f<T>();
}
};
Of course the compiler can easily inline g() throwing away the wrapping call, so there is no performance hit on this alternative.
One solution would be to forward from the function, you want to overload to some implementation that depends on the classes template arguments:
template < typename T >
struct foo {
void f();
};
template < typename T >
struct f_impl {
static void impl()
{
// default implementation
}
};
template <>
struct f_impl<int> {
static void impl()
{
// special int implementation
}
};
template < typename T >
void foo< T >::f()
{
f_impl< T >::impl();
}
Or just use private functions, call them with the template parameter and overload them.
template < typename T >
class foo {
public:
void f()
{
impl(T());
}
private:
template < typename G >
void impl( const G& );
void impl( int );
};
Or if it's really just one special situation with a very special type, just query for that type in the implementation.
With enable_if:
#include <iostream>
#include <type_traits>
template <typename T>
class A {
private:
template <typename U>
static typename std::enable_if<std::is_same<U, char>::value, char>::type
g() {
std::cout << "char\n";
return char();
}
template <typename U>
static typename std::enable_if<std::is_same<U, int>::value, int>::type
g() {
std::cout << "int\n";
return int();
}
public:
static T f() { return g<T>(); }
};
int main(void)
{
A<char>::f();
A<int>::f();
// error: no matching function for call to ‘A<double>::g()’
// A<double>::f();
return 0;
}
Tag dispatching is often the clean way to do this.
In your base method, use a traits class to determine what sub version of the method you want to call. This generates a type (called a tag) that describes the result of the decision.
Then perfect forward to that implememtation sub version passing an instance of the tag type. Overload resolution kicks in, and only the implememtation you want gets instantiated and called.
Overload resolution based on a parameter type is a much less insane way of handling the dispatch, as enable_if is fragile, complex at point of use, gets really complex if you have 3+ overloads, and there are strange corner cases that can surprise you with wonderful compilation errors.
Maybe i'm wrong but chosen best anwser provided by Manu343726 has an error and won't compile. Both operator overloads have the same signature. Consider best anwser in question std::enable_if : parameter vs template parameter
P.S. i would put a comment, but not enough reputation, sorry