Reputation: 8036
Hallo!
I would like to specialise only one of two template types. E.g. template <typename A, typename B> class X
should have a special implementation for a single function X<float, sometype>::someFunc()
.
Sample code:
main.h:
#include <iostream>
template <typename F, typename I>
class B
{
public:
void someFunc()
{
std::cout << "normal" << std::endl;
};
void someFuncNotSpecial()
{
std::cout << "normal" << std::endl;
};
};
template <typename I>
void B<float, I>::someFunc();
main.cpp:
#include <iostream>
#include "main.h"
using namespace std;
template <typename I>
void B<float, I>::someFunc()
{
cout << "special" << endl;
}
int main(int argc, char *argv[])
{
B<int, int> b1;
b1.someFunc();
b1.someFuncNotSpecial();
B<float, int> b2;
b2.someFunc();
b2.someFuncNotSpecial();
}
Compilation fails for class B
. Is it true, that this is not possible in C++ in this way? What would be the best workaround?
[edit]
template <float, typename I>
void B<float, I>::someFunc();
leads to
main.h:26: error: ‘float’ is not a valid type for a template constant parameter
template <typename I>
void B<float, I>::someFunc();
leads to
main.h:27: error: invalid use of incomplete type ‘class B’
And I'm using gcc.
[edit]
I don't want to specialise the whole class, as there are other functions that don't have a specialisation.
Upvotes: 16
Views: 26209
Reputation: 25
I think C++ expert Mayer provides us an elegant function. Cons is it depends on GCC feature.
#include <map>
#include <iostream>
#include <string>
using namespace std;
template<typename... T>
void TemplatePrint(T... args) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
map<string, int> arr={{"1", 1}, {"2", 2}, {"3", 3}};
auto itr = arr.find("3");
TemplatePrint<decltype(itr)>(itr);
return 0;
}
GCC will print out real decltype of iterator (really real), which is :
void TemplatePrint(T ...) [with T = {std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> >}]
Upvotes: 0
Reputation: 1
Solution 1. move all implementation to a base class like B_Base. then specialize on float to override the someFunc. like below
template <typename F, typename I>
class B : B_Base<F, I>
{
}
template <typename I>
class B<float, I> : B_Base<flat, I>
{
public:
void someFunc() {....}
};
Solution 2. use function overload, put float as input or boost::is_same to dispatch. unfortunately, you function someFunc doesn't have parameter. so it need change the interface.
Upvotes: 0
Reputation: 2226
Although you can totally specialize member functions of a class template, you cannot _partially specialize member functions. - Andrei Alexandrescu
Partial Class specialization is explained by the other posters.
You can, however, use overloading:
template <class T, class U> T fun(U obj); // primary template
template <class U> void Fun<void, U>(U obj); // illegal pertial
// specialization
template <class T> T fun (Window obj); // legal (overloading)
If you want to go deep into this, you can read about this issue in depth in "Modern C++ Design" by A. Alexandrescu.
Upvotes: 7
Reputation: 56956
You have to provide a partial specialization of the class template B
:
template <typename I>
class B<float, I>
{
public:
void someFunc();
};
template <typename I>
void B<float, I>::someFunc()
{
...
}
You can also just define someFunc
inside the specialization.
However, if you only want to specialize a function, and not a class do e. g.
template <typename F, typename I>
void someFunc(F f, I i) { someFuncImpl::act(f, i); }
template <typename F, typename I>
struct someFuncImpl { static void act(F f, I i) { ... } };
// Partial specialization
template <typename I>
struct someFuncImpl<float, I> { static void act(float f, I i) { ... } };
But you can't specialize a function template without this trick.
Upvotes: 26