Explicit specialization of members of class templates - c++

Trying to nail down the logic behind explicit specialization of members of class templates I composed this code below:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<> template<class V>
void X<int>::Y<int>::f(int, V) {}
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
It compiles without any problems. But when i introduce changes shown below, it refuses to compile at all:
#include <iostream>
using namespace std;
template<class T> class X
{
public:
template<class U> class Y
{
public:
template<class V> void f(U,V);
void g(U);
};
};
template<> template<class U> template<class V> // changes
void X<int>::Y<U>::f(U, V) {} // changes
int main() {
X<int>::Y<int> b;
b.f(1, 1);
}
Error:
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3860: template argument list following class template name must list parameters in the order used in template parameter list
1>d:\projects\programs\youtube\lesson\lesson\main.cpp(17): error C3855: 'X': template parameter 'T' is incompatible with the declaration
Can somebody explain to me what is going on here? Thank you!

Related

Partial template specialization using nested (undefined yet) type of a forward-declared class

There is a way to make a partial template specialization for a forward-declared (incomplete) type (answer).
But after seeing the mentioned question I wondered if it is possible to define a partial specialization for a class template using an incomplete nested (and possibly private) class.
In C++ currently one can't forward-declare a nested class without defining the class:
class undefined;
class undefined::foo; // impossibru
With some hacks I made a working code (for a sake of research): https://godbolt.org/z/9W8nfhx8P
#include <iostream>
template <typename T, typename = T>
struct specialize;
// workaround to get to a nested foo
template <typename T, typename...>
struct mem_foo
{
// error: 'struct undefined::foo' is private within this context
using type = typename T::foo;
};
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename mem_foo<undefined, MemFoo>::type, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private: // will not compile without friend
struct foo{
std::string name = "John Cena";
};
friend struct mem_foo<undefined, foo>; // ugly
// friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
But for a private types an ugly friend is used. friend struct specialize<undefined::foo>; would be more semantically appealing.
Is there another or more elegant solution?
A more elegant/less convoluted solution: https://godbolt.org/z/3vrfPWP5f
#include <iostream>
template <typename T, typename = T>
struct specialize;
template <typename T, typename ...>
struct defer_instantiation
{
using type = T;
};
template <typename T, typename ... R>
using defer_instantiation_t = typename defer_instantiation<T, R...>::type;
class undefined;
// class undefined::foo; // impossibru
template <typename MemFoo>
struct specialize<typename defer_instantiation_t<undefined, MemFoo>::foo, MemFoo>
{
void operator()(const MemFoo &f) const
{
// this will compile however
std::cout << f.name << std::endl;
}
};
#include <string>
class undefined
{
private:
struct foo{
std::string name = "John Cena";
};
friend struct specialize<foo>; // this is irrelevant, but would be nicer than mem_foo
public:
static foo get() { return {}; }
};
int main()
{
specialize</*undefined::foo*/decltype(undefined::get())>{}(undefined::get());
return 0;
}
It allowes to reference yet non-existing member types of a yet incomplete class via a deferred template instantiation.

Access private template with friend declaration

Class B uses a use a template, which is a private member of class A.
I tried friend declaration but the template is still private within the context.
How to allow B to use a private template of A?
Test (also at godbolt.org):
#include <iostream>
#include <vector>
template <class T>
class A {
private:
template<typename R> using V = std::vector<R>;
};
template <typename T, class Prev>
class B {
public:
friend Prev;
typename Prev::template V<T> v_;
};
int main() {
B<int, A<int>> b;
return 0;
}
Compilation Error:
error: ‘template<class R> using V
= std::vector<R, std::allocator<_CharT> >’
is private within this context
typename Prev::template V<T> v_;
^~
Fix (also at godbolt.org)
#include <iostream>
#include <vector>
template <typename T, class Prev> class B;
template <class T>
class A {
template <typename T2, class Prev>
friend class B;
private:
template<typename R> using V = std::vector<R>;
};
template <typename T, class Prev>
class B {
public:
typename Prev::template V<T> v_;
};
int main() {
B<int, A<int>> b;
return 0;
}

Template Specialization for member functions

I've recently discovered template specialization in C++.
template <typename T>
void fct(void) {}
template <>
void fct<int>(void) {}
int main(void) {
fct<int>();
return 0;
}
I'd like to use template specialization for member functions inside a class.
class MyClass {
public:
template <typename T>
static void fct(void) {}
template <>
static void fct<int>(void) {}
};
int main(void) {
MyClass::fct<int>();
return 0;
}
Unfortunately, compiling with g++ gives me the following error:
error: explicit specialization in non-namespace scope ‘struct MyClass’
error: template-id ‘toto<int>’ in declaration of primary template
I've noticed that doing template specialization works in main scope or in a namespace but not in a struct or in a class.
I've found something on stackoverflow about using a namespace like in the following code:
namespace myNameSpace {
template <typename T>
void fct(void) {}
template <>
void fct<int>(void) {}
}
class MyClass {
public:
template <typename T>
static void fct(void) {
myNameSpace::fct<T>();
}
};
int main(void) {
MyClass::fct<int>();
return 0;
}
What am I doing wrong? Is it possible to make template specialization with member functions? If not, what is the best way to get around this? Is there a better way than using namespace to get around this?
Write the specialization after the class definition:
class MyClass
{
public:
template <typename T>
static void fct(void) {}
};
template <>
void MyClass::fct<int>() {}

Template Inside Template Class

I have a class that looks like this:
template <typename P>
class Pack {
Public:
template <typename X>
Private:
Other T <other>
};
I want to write the function outside of the class but I am having difficulties defining the header.. I tried something like this:
template <typename X>
int Pack<X>::pop(X led) const{
// Do something in here with Other from the private above
}
But this does not work it keeps saying "Out of line definition of pop, does not match any definitions of P.
Any help is appreciated thanks!
Clarification: Trying to Implement the function stub so I can write the code outside of the class.
Your code looks incomplete and you're posting small chunks of it from time to time but I believe this syntax is what you want:
#include <iostream>
using namespace std;
template <typename P>
class Stack {
public:
template <typename X> int pop(X pred) const;
};
template <typename P>
template<typename X>
int Stack<P>::pop(X pred) const{
return 0;
}
int main() {
Stack<bool> obj;
char a;
obj.pop(a);
return 0;
}
http://ideone.com/Cp69hg

Specializing constructor of class template

I want to specialize a constructor of a class template. This doesn't work:
template<typename T>
struct One {};
template<typename T>
struct Two {};
template<template<typename> class T, template<typename> class U>
struct Three : public T<Three<T, U>>, public U<Three<T, U>> {};
template<typename T> struct Four;
template<typename T>
struct Four
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
int main(int argc, char *argv[])
{
Four<Three<One, Two> > obj;
}
but changing the class template definition to this works:
template<typename T> struct Four;
template<template<typename> class T, template<typename> class U>
struct Four<Three<T, U>>
{
Four();
};
template<template<typename> class T, template<typename> class U>
Four<Three<T, U>>::Four() {}
This seems like I'm specializing the entire class template. However I want to specialize only the constructor as in the code above - the one that doesn't work. Why can't I specialize the constructor of Four for just Three (I'm not changing the signature of the ctor of the class template)?
You can't. You must specialize the whole class. But.. you can use inheritance as a work around:
#include <iostream>
class something {};
template <typename T> class hidden_base {
public: hidden_base() {a = 1;}
protected: int a;
};
template<> class hidden_base<something> {
public: hidden_base() {a = 2;}
protected: int a;
};
template <typename T>
class your_class : public hidden_base<T> {
public:
void lots();
void of();
void other();
void member();
void functions();
void here();
void show_a() {std::cout << hidden_base<T>::a << std::endl;}
};
int main() {
your_class<long>().show_a();
your_class<int>().show_a();
your_class<something>().show_a();
}
This will print:
1
1
2