I have a template class that has a template member function that needs to be specialized, as in:
template <typename T>
class X
{
public:
template <typename U>
void Y() {}
template <>
void Y<int>() {}
};
Altough VC handles this correctly, apperantly this isn't standard and GCC complains: explicit specialization in non-namespace scope 'class X<T>'
I tried:
template <typename T>
class X
{
public:
template <typename U>
void Y() {}
};
template <typename T>
// Also tried `template<>` here
void X<T>::Y<int>() {}
But this causes both VC and GCC to complain.
What's the right way to do this?
Very common problem. One way to solve it is through overloading
template <typename T>
struct type2type { typedef T type; };
template <typename T>
class X
{
public:
template <typename U>
void Y() { Y(type2type<U>()); }
private:
template<typename U>
void Y(type2type<U>) { }
void Y(type2type<int>) { }
};
Use a Helper class to remove the class specialization
Example 1
namespace {
/* Make this work
template <typename T>
class X
{
public:
template <typename U>
void Y() {}
template <>
void Y<int>() {}
};
*/
template <typename K>
struct IntegerHelper {
static bool isInteger() { return false; }
};
template <>
inline bool IntegerHelper<int>::isInteger() {
return true;
}
template <typename T>
class TestX {
public:
template <typename K>
static bool isInteger() {
return IntegerHelper<K>::isInteger();
}
};
}
TEST(TestTemplateMethodSpecialization, Basic) {
EXPECT_TRUE(TestX<double>::isInteger<int>());
EXPECT_FALSE(TestX<double>::isInteger<double>());
}
Example 2
enum class Side {
BUY = 0,
SELL
};
using PriceType = int64_t;
class BookHelper {
public:
BookHelper(
PriceType insideBuyPrice,
PriceType insideSellPrice)
:
insideBuyPrice_{insideBuyPrice},
insideSellPrice_{insideSellPrice}
{ }
template <Side SideV>
PriceType insidePrice() const;
template <Side SideV>
void insidePrice(PriceType price);
private:
PriceType insideBuyPrice_;
PriceType insideSellPrice_;
};
template <>
inline void BookHelper::insidePrice<Side::BUY>(PriceType price) {
insideBuyPrice_ = price;
}
template <>
inline void BookHelper::insidePrice<Side::SELL>(PriceType price) {
insideSellPrice_ = price;
}
template <>
inline PriceType BookHelper::insidePrice<Side::BUY>() const {
return insideBuyPrice_;
}
template <>
inline PriceType BookHelper::insidePrice<Side::SELL>() const {
return insideSellPrice_;
}
template <typename BookT>
class Book {
public:
Book();
template <Side SideV>
PriceType insidePrice() const;
template <Side SideV>
void insidePrice(PriceType price);
private:
std::unique_ptr<BookHelper> helper_;
};
template<typename BookT>
Book<BookT>::Book() :
helper_{new BookHelper{std::numeric_limits<PriceType>::min(), std::numeric_limits<PriceType>::max()}}
{}
template <typename BookT>
template <Side SideV>
PriceType Book<BookT>::insidePrice() const {
return helper_->insidePrice<SideV>();
}
template <typename BookT>
template <Side SideV>
void Book<BookT>::insidePrice(PriceType price) {
helper_->insidePrice<SideV>(price);
}
class TestBook { };
int main() {
Book<TestBook> test;
test.insidePrice<Side::SELL>(1230046);
test.insidePrice<Side::BUY>(1230045);
std::cout << " inside SELL price : " << test.insidePrice<Side::SELL>() << std::endl;
std::cout << " inside BUY price : " << test.insidePrice<Side::BUY>() << std::endl;
}
Related
What is the correct syntax to specialize a templated member function of a templated class without specifying the class template parameter?
Here is what I mean:
Example #1 (works):
#include <iostream>
struct C1
{
template <class B>
void f(void) const;
};
template <>
void C1::f<int>(void) const { std::cout<<777<<std::endl; }
int main(void)
{
C1 c1; c1.f<int>();
}
Example #2 (works):
#include <iostream>
template <class A>
struct C2
{
template <class B>
void f(void) const;
};
template <>
template <>
void C2<int>::f<int>(void) const { std::cout<<888<<std::endl; }
int main(void)
{
C2<int> c2; c2.f<int>();
return 0;
}
Example #3 (does not compile: "enclosing class templates are not explicitly specialized"):
#include <iostream>
template <class A>
struct C3
{
template <class B>
void f(void) const;
};
struct D { static int g(void){ return 999; } };
template <class A>
template <>
void C3<A>::f<int>(void) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
template <>
void C3<A>::f<char>(void) const { std::cout<<A::g()+2<<std::endl; }
int main(void)
{
C3<D> c3a; c3a.f<int >(); // expect to see 1000
C3<D> c3b; c3b.f<char>(); // expect to see 1001
return 0;
}
How can I make example #3 work?
You can use a technique called tag dispatch and replace the template specialisations by function overloads.
template<typename>
struct Tag {};
template <class A>
struct C3
{
void f_impl(Tag<int>) const;
void f_impl(Tag<char>) const;
template<class B>
void f() const {
f_impl(Tag<B>{});
}
};
struct D { static int g(void){ return 999; } };
template <class A>
void C3<A>::f_impl(Tag<int>) const { std::cout<<A::g()+1<<std::endl; }
template <class A>
void C3<A>::f_impl(Tag<char>) const { std::cout<<A::g()+2<<std::endl; }
Then your call site looks exactly as you want:
C3<D> c3; c3.f<int>(); // expect to see 1000
C3<D> c4; c4.f<char>(); // expect to see 1001
Full example here.
I want to do multiple inheritance via template arguments and pass reference to this in each base class, so I can call top level object's method from each base class's method. I can do it with manual inheritance, but I want to be able to do this via templates arguments.
Godbolt link
Godbolt link with manual inheritance
#include <cstdio>
template <typename T>
struct Foo {
Foo(T &t)
: t_(t) {
}
void foo() {
t_.call("foo");
}
T &t_;
};
template <typename T>
struct Bar {
Bar(T &t)
: t_(t) {
}
void bar() {
t_.call("bar");
}
T &t_;
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl>... {
Impl()
: Methods<Impl>(*this)... {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
I tried this approach, but it gives
type/value mismatch at argument 1 in template parameter list for 'template<class> class ... Methods'
Thanks to #Nicol Bolas, he advised to use static_cast and CRTP for this
#include <cstdio>
template <typename T>
struct Foo {
void foo() {
static_cast<T*>(this)->call("foo");
}
};
template <typename T>
struct Bar {
void bar() {
static_cast<T*>(this)->call("bar");
}
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl<Methods...>>... {
Impl() {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
I got a BaseType which is templated and want to inheritance it with an ArrayItem class. Since i want to use them as stencil for memory i want the ArrayItem class to know which type we have. So i'd like to specialize the constructor for some of the Template values for example long long.
template<typename T>
class ArrayItem : public BaseType<T>
{
public:
inline ArrayItem(T& t);
inline ETypes getType();
private:
ETypes m_type;
};
And the hpp should look like this:
template <typename T>
ArrayItem<T>::ArrayItem (T& t): BaseType(t)
{
}
template <>
ArrayItem<long long>::ArrayItem(long long& t) : BaseType<long long>(t) // this
{
m_type = INT;
}
template<typename T>
inline ETypes ArrayItem<T>::getType()
{
return m_type;
}
But the how do i do this specialization here?
enum ETypes
{
INT,
BOOL,
OBJECT,
ARRAY,
DOUBLE,
STRING
};
template <typename T>
class BaseType
{
public:
BaseType();
explicit BaseType(T& t);
protected:
union DataUnion
{
T data;
size_t size; //to make it at least 64bit
explicit DataUnion(T& t);
} m_data;
};
template <typename T>
BaseType<T>::DataUnion::DataUnion(T& t)
{
this->data = t;
}
template <typename T>
BaseType<T>::BaseType(T& t) : m_data(t) {}
template<typename T>
class ArrayItem : public BaseType<T>
{
public:
explicit inline ArrayItem(T& t);
inline ETypes getType();
private:
ETypes m_type;
};
template <typename T>
ArrayItem<T>::ArrayItem (T& t): BaseType<T>(t)
{
}
template <>
ArrayItem<long long>::ArrayItem(long long& t) : BaseType<long long>(t) // this
{
m_type = INT;
}
template<typename T>
inline ETypes ArrayItem<T>::getType()
{
return m_type;
}
int main()
{
long long somenumber = 1234;
ArrayItem<long long> item(somenumber);
if(item.getType() == INT)
std::cout<< "inttype";
//after this we can stancil the ptr to a
//BaseType<long long> since we know it's a long here
}
What you have looks right to me, outside of not providing the template arguments to BaseType for the typical case.
Here's a simple demo:
#include <iostream>
template <typename T>
struct B { };
template <typename T>
struct D : B<T> {
D(T );
};
template <typename T>
D<T>::D(T )
: B<T>()
{
std::cout << "def\n";
}
template <>
D<long>::D(long )
: B<long>()
{
std::cout << "hi\n";
}
int main()
{
D<int> i(4); // prints def
D<long> l(5); // prints hi
}
I wonder whether the below tricky situation is possible:
Suppose I have a template class template <typename DTYPE> class A{};, where DTYPE is supposed to be one of uint8_t, uint16_t, etc. I want to add a friend class to A, but this friend class differs for each DTYPE alternative. Further, suppose the friend classes for different DTYPE values are not instantiations of another template class, but independent classes.
Is there a way to do it?
You can add template "proxy" class FriendOfA and specialize it for whatever type you need:
// actual friends
class FriendUint8 {};
class FriendUint16 {};
template<typename T> struct FriendOfA;
template<>
struct FriendOfA<uint8_t> {
typedef FriendUint8 type;
};
template<>
struct FriendOfA<uint16_t> {
typedef FriendUint16 type;
};
// optional helper
template <typename T>
using FriendOfA_t = typename FriendOfA<T>::type;
template<class T>
class A {
friend typename FriendOfA<T>::type;
// or simply
friend FriendOfA_t<T>;
};
I believe you're looking for something like that:
#include <iostream>
struct BaseFriend
{
template <typename T>
void boo(const T& t) { t.foo(); }
};
struct BaseFriendProxy
{
template <typename T>
void boo(const T& t) { std::cout << "Proxy: "; t.foo(); }
};
template <typename TType>
struct Friend ;
template <>
struct Friend<int> {
using T = BaseFriend;
};
template <>
struct Friend<char> {
using T = BaseFriendProxy;
};
template <typename DTYPE>
class A
{
private:
friend typename Friend<DTYPE>::T;
void foo() const
{ std::cout << "A::foo()" << std::endl; }
};
int main()
{
A<int> a;
BaseFriend bf1;
bf1.boo(a);
A<char> b;
BaseFriendProxy bf2;
bf2.boo(b);
return 0;
}
But this will work only with C++11: you can't combine friend class ... with typename X::Y in C++03
Sure you can, specialize your template and add whatever friend class you want:
#include <iostream>
using namespace std;
class base {
public:
virtual int getValue() = 0;
};
class friend1 {
public:
base* ptr;
int getValue() {
return ptr->getValue();
}
};
class friend2 {
public:
base* ptr;
int getValue() {
return ptr->getValue();
}
};
template <typename DTYPE> class A : public base{
public:
A() { data = 42; }
// No friends
private:
int data;
int getValue() {
return data;
}
};
template <> class A<char> : public base{
public:
A() { data = 44; }
friend class friend1;
private:
int data;
int getValue() {
return data;
}
};
template <> class A<bool> : public base{
public:
A() { data = 45; }
friend class friend2;
private:
int data;
int getValue() {
return data;
}
};
int main()
{
A<char> obj1;
friend1 friend_of_obj1;
friend_of_obj1.ptr = &obj1;
cout << friend_of_obj1.getValue() << endl;
A<bool> obj2;
friend2 friend_of_obj2;
friend_of_obj2.ptr = &obj2;
cout << friend_of_obj2.getValue();
}
http://ideone.com/hM9x0y
Yes, a friend can be based on a template. Such as;
template <typename DTYPE>
struct Friend;
template <class DTYPE>
class A {
friend struct Friend<DTYPE>;
};
For each type DTYPE for the class A you wish to support (different by implementation) you can specialise Friend, such as;
template<>
struct Friend<uint8_t> {
// ...
};
A basic working sample:
#include <cstdint>
using namespace std;
template<typename T>
struct Friend;
template <class T>
class A {
friend struct Friend<T>;
int i = 0;
};
template<>
struct Friend<uint8_t> {
void method() {
A<uint8_t> a;
a.i = 8;
}
};
template<>
struct Friend<uint16_t> {
void method() {
A<uint16_t> a;
//A<uint8_t> b; // fails to compile
a.i = 16;
}
};
int main()
{
A<uint8_t> a;
Friend<uint8_t> f;
f.method();
}
template <typename T, typename C>
class CSVWriter{
template <typename PrinterT>
void write(std::ostream& stream, const PrinterT& printer){
}
};
I want to check whether there exists at least two overloads PrinterT::operator()(T*) and PrinterT::operator()(C*)
PrinterT may or may not inherit from std::unary_function
What concept Checking Classes I need to use here ?
(I am not using C++11)
You can use something like that
#include <iostream>
#include <boost/concept/requires.hpp>
#include <boost/concept/usage.hpp>
template <class Type, class Param>
class has_operator_round_brackets_with_parameter
{
public:
BOOST_CONCEPT_USAGE(has_operator_round_brackets_with_parameter)
{
_t(_p);
}
private:
Type _t;
Param _p;
};
struct X {};
struct Y {};
struct Test1
{
void operator() (X*) const { }
};
struct Test2: public Test1
{
void operator() (X*) const { }
void operator() (Y*) const { }
};
template <class T, class C>
struct CSVWriter
{
template <class PrinterT>
BOOST_CONCEPT_REQUIRES(
((has_operator_round_brackets_with_parameter<PrinterT, T*>))
((has_operator_round_brackets_with_parameter<PrinterT, C*>)),
(void)) write(std::ostream& stream, const PrinterT& printer)
{
}
};
int main()
{
CSVWriter<X, Y> w;
// w.write<Test1>(std::cout, Test1()); // FAIL
w.write<Test2>(std::cout, Test2()); // OK
return 0;
}