Next code:
#include <typeinfo>
#include <iostream>
struct A
{
A() : _m('a'){ std::cout << "A()" << std::endl; }
void f(){ std::cout << "A::f() " << _m << std::endl; }
char _m;
};
struct B
{
B() : _m('b'){ std::cout << "B()" << std::endl; }
void f(){ std::cout << "B::f() " << _m << std::endl; }
char _m;
};
struct C
{
C() : _m('c'){ std::cout << "C()" << std::endl; }
void f(){ std::cout << "C::f() " << _m << std::endl; }
char _m;
};
template<typename T>
void f(T t = T());
template<typename T>
void f(T t)
{
std::cout << typeid(t).name() << std::endl;
t.f();
}
int main()
{
f<A>();
f<B>();
f<C>();
}
Has this output when using VS2008, VS2010 and VS2012:
A()
struct A
A::f() a
A()
struct B
B::f() a
A()
struct C
C::f() a
Is this a known compiler bug?
Please note that it works as expected in VS2013.
Your compiler might be confused because you have a function template declaration, followed by something that looks like a function template partial specialization. GCC correctly rejects your code.
To be precise, this is the problem:
template<typename T>
void f<T>(T t) { .... }
// ^^^
If you really want to separate declaration and definition, you would need
template<typename T>
void f(T t) { .... }
This would be a well-formed version of your program:
#include <iostream>
#include <typeinfo>
struct A {}; // as before
struct B {}; // as before
struct C {}; // as before
template<typename T>
void f(T t = T())
{
std::cout << typeid( t ).name() << std::endl;
t.f();
}
int main()
{
f<A>();
f<B>();
f<C>();
}
Related
Is there an way to call different constructors of same class based on different template parameter.
template<class T>
class X {
public:
T a;
X<char>() {
std::cout << "char ctor called" << std::endl;
}
X<int>() {
std::cout << "int ctor called" << std::endl;
}
};
int main() {
X<char> x;
X<int> y;
}
I think constructors in the class are not valid, but is there any other way to do that?
There are several ways:
(full) specialization of the member:
template<class T>
class X {
public:
T a;
X();
};
template <>
X<char>::X() : a('\0') { std::cout << "char ctor called" << std::endl; }
template <>
X<int>::X() : a(0) { std::cout << "int ctor called" << std::endl; }
Specialize the whole class (so requires to duplicate some code though)
template<class T>
class X;
template <>
class X<char> {
public:
char a;
X() : a('\0') { std::cout << "char ctor called" << std::endl; }
};
template <>
class X<int> {
public:
int a;
X() : a(0) { std::cout << "int ctor called" << std::endl; }
};
if constexpr of C++17 (but doesn't handle initializer list):
template<class T>
class X {
public:
T a;
X() : a(0) {
if constexpr (std::is_same_v<char, T>) {
std::cout << "char ctor called" << std::endl;
} else if constexpr (std::is_same_v<int, T>) {
std::cout << "int ctor called" << std::endl;
}
}
};
requires for C++20:
template<class T>
class X {
public:
T a;
X() requires(std::is_same_v<char, T>) : a('\0') {
std::cout << "char ctor called" << std::endl;
}
X() requires(std::is_same_v<int, T>) : a(0) {
std::cout << "int ctor called" << std::endl;
}
};
You can use if constexpr:
template <class T>
class X {
public:
// ...
X()
{
if constexpr (std::is_same_v<T, int>) {
// ...
} else if constexpr (std::is_same_v<T, char>) {
// ...
} else {
// ...
}
}
};
Just another alternative - tag dispatch:
template<class T>
class X {
public:
// ...
X() : X(Tag<T>{}) {}
private:
template<class> struct Tag {};
X(Tag<char>) {
// ...
}
X(Tag<int>) {
// ...
}
template<class U> X(Tag<U>) {
// ...
}
};
Yes,see http://www.cplusplus.com/doc/oldtutorial/templates/
You can do this:
template<class T>
class X {
public:
T a;
X() {
std::cout << "basic template\n" ;
}
};
template<>
class X<char> {
public:
char a;
X() {
std::cout << "char ctor called\n" ;
}
};
template<>
class X<int> {
public:
int a;
X() {
std::cout << "int ctor called\n";
}
};
int main(){
X<int> xint;
X<char> xchar;
X<string> xstring;
return 0;
}
You will see in the output window:
int ctor called
char ctor called
basic template
Based on this SO answer, I was experimenting with something similar but with a pointer:
#include <iostream>
class Bar {
public:
virtual ~Bar() {}
};
class Foo: Bar {
public:
Foo() { std::cout << "Foo::Foo()" << std::endl; }
~Foo() override { std::cout << "Foo::~Foo()" << std::endl; }
};
class Faz {
public:
Faz() { std::cout << "Faz::Faz()" << std::endl; }
~Faz() { std::cout << "Faz::~Faz()" << std::endl; }
};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, std::remove_pointer<T>>::value>::type
func(char const* type, T) {
std::cout << type << " is derived from Bar" << std::endl;
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, std::remove_pointer<T>>::value>::type
func(char const* type, T) {
std::cout << type << " is NOT derived from Bar" << std::endl;
}
int main()
{
func("std::unique_ptr<Foo>", std::unique_ptr<Foo>());
func("std::unique_ptr<Faz>", std::unique_ptr<Faz>());
}
cout is :
std::unique_ptr<Foo> is NOT derived from Bar
std::unique_ptr<Faz> is NOT derived from Bar
Why does !std::is_base_of<Bar, type_identity<std::remove_pointer<T>>>::value always evaluate as true? I assumed (as a beginner):
std::unique_ptr<Foo> is derived from Bar
std::unique_ptr<Faz> is NOT derived from Bar
I'm probably missing something stupid.
std::remove_pointer<> acts on raw pointer types.
The smart pointer's type is not related to the class hierarchy of referent type
[Edit: Turns out we don't even need reinterpret cast, making this even simpler]
This came up here and I found a better solution using reinterpret cast and shared pointer aliasing constructor. It allows both the ctor and dtor to be private, as well as use of the final specifier.
The reputation system won't let me leave this as an answer in that question, so I had to provide it as another question...
#include <iostream>
#include <memory>
class Factory final {
public:
template<typename T, typename... A>
static std::shared_ptr<T> make_shared(A&&... args) {
auto ptr = std::make_shared<Type<T>>(std::forward<A>(args)...);
return std::shared_ptr<T>(ptr, &ptr->type);
}
private:
template<typename T>
struct Type final {
template<typename... A>
Type(A&&... args) : type(std::forward<A>(args)...) { std::cout << "Type(...) addr=" << this << "\n"; }
~Type() { std::cout << "~Type()\n"; }
T type;
};
};
class X final {
friend struct Factory::Type<X>; // factory access
private:
X() { std::cout << "X() addr=" << this << "\n"; }
X(int i) { std::cout << "X(...) addr=" << this << " i=" << i << "\n"; }
~X() { std::cout << "~X()\n"; }
};
int main() {
auto ptr1 = Factory::make_shared<X>();
auto ptr2 = Factory::make_shared<X>(42);
}
Giving the following output under gcc...
X() addr=0x62bc30
Type(...) addr=0x62bc30
X(...) addr=0x62bc50 i=42
Type(...) addr=0x62bc50
~Type()
~X()
~Type()
~X()
Just a followup... The approach above doesn't play well with std::enable_shared_from_this<> because the initial std::shared_ptr<> is to the wrapper and not the type itself. We can address this with an equivalent class that is compatible with the factory...
#include <iostream>
#include <memory>
template<typename T>
class EnableShared {
friend class Factory; // member access
public:
std::shared_ptr<T> shared_from_this() { return weak.lock(); }
protected:
EnableShared() = default;
virtual ~EnableShared() = default;
EnableShared<T>& operator=(const EnableShared<T>&) { return *this; } // no slicing
private:
std::weak_ptr<T> weak;
};
class Factory final {
public:
template<typename T, typename... A>
static std::shared_ptr<T> make_shared(A&&... args) {
auto ptr = std::make_shared<Type<T>>(std::forward<A>(args)...);
auto alt = std::shared_ptr<T>(ptr, &ptr->type);
assign(std::is_base_of<EnableShared<T>, T>(), alt);
return alt;
}
private:
template<typename T>
struct Type final {
template<typename... A>
Type(A&&... args) : type(std::forward<A>(args)...) { std::cout << "Type(...) addr=" << this << "\n"; }
~Type() { std::cout << "~Type()\n"; }
T type;
};
template<typename T>
static void assign(std::true_type, const std::shared_ptr<T>& ptr) {
ptr->weak = ptr;
}
template<typename T>
static void assign(std::false_type, const std::shared_ptr<T>&) {}
};
class X final : public EnableShared<X> {
friend struct Factory::Type<X>; // factory access
private:
X() { std::cout << "X() addr=" << this << "\n"; }
X(int i) { std::cout << "X(...) addr=" << this << " i=" << i << "\n"; }
~X() { std::cout << "~X()\n"; }
};
int main() {
auto ptr1 = Factory::make_shared<X>();
auto ptr2 = ptr1->shared_from_this();
std::cout << "ptr1=" << ptr1.get() << "\nptr2=" << ptr2.get() << "\n";
}
This code:
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
void x(const T& t) {
std::cout << "template" << std::endl;
}
void x(const A*& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
template <typename T>
void y(T t) {
std::cout << "template" << std::endl;
}
void y(A* a) {
std::cout << "a" << std::endl;
}
void y(int a) {
std::cout << "int" << std::endl;
}
template <typename T>
void z(const T& t) {
std::cout << "template" << std::endl;
}
};
// Does not compile
// template <>
// void C::z(const A*& a) {
// std::cout << "a" << std::endl;
// }
template <>
void C::z(const int& a) {
std::cout << "int" << std::endl;
}
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
c.y(new A());
c.y(new B());
c.y(1);
c.z(new A());
c.z(new B());
c.z(1);
}
Prints:
template
template
int
a
template
int
template
template
int
I have the following questions about that:
Why does void C::z(const int& a) compile but void C::z(const A*& a) does not?
What is a reasonable solution to problem? I need to have a templated function for generically handling a wide variety of arguments, but a large set of classes with a common base needs to be handled specifically. I need some approach that will print a a int.
Edit: Thanks to the suggestion of #AndyG I was able to resolve this with some type_traits and the code below:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
typename boost::disable_if<boost::is_base_of<A, typename boost::remove_pointer<T>::type>, void>::type x(const T& t) {
std::cout << "template" << std::endl;
}
void x(A*const& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
};
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
}
The answer is because a const on a pointer type is a little weird.
What you want is this:
template <>
void C::z( A*const& a) {
std::cout << "a" << std::endl;
}
const needs to be read right to left. Since z accepts a T&, when you want to specialize for A* you need to place the const after A* instead of in front.
Demo
I have a templated class pair, and I'd like to write a show function outside of the class to do some fancy couting. When specifying the template type in show explictly, it all works as expected:
#include <iostream>
template <class A_Type>
class pair
{
public:
A_Type a0;
A_Type a1;
};
void show(const pair<double> & p) {
std::cout << p.a0 << std::endl;
std::cout << p.a1 << std::endl;
}
int main() {
pair<double> p;
p.a0 = 1.2;
p.a1 = 1.3;
show(p);
}
I'd like to have show oblivious of the template type though.
Any hints?
You can change show function to:
template<typename DataType>
void show(const pair<DataType> & p) {
std::cout << p.a0 << std::endl;
std::cout << p.a1 << std::endl;
}
Or a better approach (in my opinion) is to make show function member of the class:
template <class A_Type>
class pair {
public:
A_Type a0;
A_Type a1;
void show() const {
std::cout << this->a0 << std::endl;
std::cout << this->a1 << std::endl;
}
};
and then simply:
int main() {
pair<double> p;
p.a0 = 1.2;
p.a1 = 1.3;
p.show();
}