C++ instantiation of function template with shared_ptrs [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ passing a derived class shared_ptr to a templated function
The compiler has no problems with instantiation when we use pointers.
template <typename T> struct Base{
virtual ~Base() {}
};
template <typename T> struct Der: public Base<T> {
};
template <class T>
void f(Base<T>* b) {}
int main() {
Der<int> x;
f(&x);
}
However if I change f to use shared_ptrs, the compiler cannot find a match.
template <class T>
void f(shared_ptr<Base<T> >b) {}
int main() {
shared_ptr<Der<int> > x(new Der<int>);
f(x);
}
Z.cc: In function ‘int main()’:
Z.cc:45: error: no matching function for call to ‘f(std::tr1::shared_ptr<Der<int> >&)’
Changing x to
shared_ptr<Base<int> > x(new Der<int>);
will also work.
Why is there this difference in behavior?

shared_ptr<Der<int>> is not implicitly convertible to shared_ptr<Base<int>> whereas Der<int>* is implicitly convertible to Base<int>*. C++ doesn't automatically make types instantiated from a template convertible just because the template parameter types happen to be convertible, because that doesn't necessarily make sense and could be dangerous.
http://www2.research.att.com/~bs/bs_faq2.html#conversion

Related

Why isn't it possible to use CRTP's types, but possible to call CRTP's methods? [duplicate]

This question already has answers here:
C++ compiler does not check if a method exists in template class
(2 answers)
Closed 6 months ago.
This code compiles and works only when calling CRTP's methods:
template <typename CRTP>
struct crtp
{
// using type = typename CRTP::type; // will not compile
void print() const
{
using type = typename CRTP::type; // compiles
static_cast<const CRTP&>(*this).print();
}
};
#include <iostream>
int main()
{
struct foo : crtp<foo>
{
using type = int;
void print() const {
std::cout << "John Cena\n";
};
} f{};
const crtp<foo>& c = f;
c.print();
return 0;
}
Upon crtp<foo>'s instantiation, foo is incomplete. But its methods can be used.
However, CRTP's types can't used dues CRTP's incompleteness outside functions.
Why is it allowed to defer a check for incompletness until a class's function is called, but not upon object's instatiation?
When using CRTP::type within the class body (uncommented), one will get a compilation error:
<source>:4:33: error: no type named 'type' in 'foo'
using type = typename CRTP::type; // will not compile
~~~~~~~~~~~~~~~^~~~
Note that even if you write a member function definition inside the class template definition, it is not instantiated when the class template is instantiated.
foo can't be defined until its base class crtp<foo> has been completely defined, but the type alias in the definition of crtp<foo> requires foo's definition to be known, which requires crtp<foo> to already be defined, which requires foo, and so on...
Member functions, on the other hand, are not compiled until after their class has been fully defined, so the type alias is fine there.
(That is, instantiating void crtp<foo>::print() const works because it only happens after foo has been defined and crtp<foo> has been instantiated.)
Separating the class template definition from the member function definition makes the two phases clearer:
template <typename CRTP>
struct crtp
{
// Can't compile unless CRTP is defined at this point.
using type = typename CRTP::type;
void print() const;
};
template <typename CRTP>
void crtp<CRTP>::print() const
{
// Also can't compile unless CRTP is defined at this point, but
// this is a later point than the class definition.
using type = typename CRTP::type;
static_cast<const CRTP&>(*this).print();
}
Within CRTP, derived classes are incomplete:
struct foo : crtp<foo> // foo incomplete here
{
using type = int;
void print() const {
// foo complete here
std::cout << "John Cena\n";
}
}; // foo complete here
foo is also complete in void crtp<foo>::print() const.

How to make class template argument deduction work inside the class itself? [duplicate]

Consider following code:
struct A {};
template <typename T> struct B
{
B(T) {}
auto foo() {return B(A{});} // error: no matching function for call to 'B<int>::B(A)'
};
auto foo() {return B(A{});} // compiles
int main()
{
foo();
B b(0);
b.foo();
}
Try it live
I understand why B::foo() doesn't compile: Inside of struct B<T>, B (as an injected-class-name) means B<T> unless it's explicitly used as a template. Which in this case prevents class template argument deduction.
Let's say I can't do auto foo() {return B<A>(A{});} since my actual code relies on slightly elaborate user-provided deduction guides.
The question is: How do I force class template argument deduction when constructing B inside of B::foo?
I hope I'm not missing something obvious.
You qualify it so that it's not the injected-class-name.
auto foo() {return ::B(A{});}
Another option is to use a function to do the type deduction for you.
template <typename T> B<T> make_b(T t) { return B<T>(t); }
and use
auto foo() {return make_b(A{});}

Why will this code build in MSVC but not Clang? [duplicate]

This question already has answers here:
C++ syntax for explicit specialization of a template function in a template class?
(9 answers)
Closed 8 years ago.
template<typename T>
class CConstraint
{
public:
CConstraint()
{
}
virtual ~CConstraint()
{
}
template <typename TL>
void Verify(int position, int constraints[])
{
}
template <>
void Verify<int>(int, int[])
{
}
};
Compiling this under g++ gives the following error:
Explicit specialization in non-namespace scope 'class CConstraint'
In VC, it compiles fine. Can anyone please let me know the workaround?
VC++ is non-compliant in this case - explicit specializations have to be at namespace scope. C++03, §14.7.3/2:
An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member.
An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.
Additionally you have the problem that you can't specialize member functions without explicitly specializing the containing class due to C++03, §14.7.3/3, so one solution would be to let Verify() forward to a, possibly specialized, free function:
namespace detail {
template <typename TL> void Verify (int, int[]) {}
template <> void Verify<int>(int, int[]) {}
}
template<typename T> class CConstraint {
// ...
template <typename TL> void Verify(int position, int constraints[]) {
detail::Verify<TL>(position, constraints);
}
};
Another way to solve it is by delegating to a private function and overloading that function. This way you still have access to member data of *this and to the outer template parameter type.
template<typename T>
struct identity { typedef T type; };
template<typename T>
class CConstraint
{
public:
template <typename TL>
void Verify(int position, int constraints[])
{
Verify(position, constraints, identity<TL>());
}
private:
template<typename TL>
void Verify(int, int[], identity<TL>)
{
}
void Verify(int, int[], identity<int>)
{
}
};
Just take the template specialization outside the class declaration.
gcc doesn't allow inline template specialization.
As another option, just deleting line
template<>
seems to work for me.
Even better: you can combine partial specialisation with default template arguments. This way modification to the VC++ code are minor, because calls to the specialised function do not need to be modified.
template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}
template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}
You may not be able to explicitly specialize the member template, but you can partially specialize it. If you add a second parameter "int dummyParam" and also add it to the specialization, it should work with both compilers.
Not that I knew this more than 10 seconds ago, but googling on the same error, I ran into this link and it worked for my member template specialization.

Full template instantiation forced in C++ template inheritance?

We all know a C++ class template does not generate member functions that are not used, as illustrated below:
template<typename T>
class A
{
public:
void WrongFunction(T t);
void RightFunction(T t);
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
Since the WrongFunction is not called in main, there's no actual code generated for it and therefore no compilation error occurs.
Now, let's introduce an abstract base class that defines the interface for class A(basically, template inheritance):
template<typename T>
class Base
{
public:
virtual void RightFunction(T t) = 0;
virtual void WrongFunction(T t) = 0;
};
template<typename T>
class A : Base<T>
{
public:
void WrongFunction(T t) override;
void RightFunction(T t) override;
};
template<typename T>
void A<T>::WrongFunction(T t)
{
std::vector<T> v;
auto a = "abc" - v;
}
template<typename T>
void A<T>::RightFunction(T t)
{
std::cout << "Success" << std::endl;
}
int main()
{
A<int> a;
a.RightFunction(2);
//a.WrongFunction(1);
return 0;
}
Suddenly, the compiler refuses to work:
prog.cc: In instantiation of 'void A::WrongFunction(T) [with T =
int]': prog.cc:39:1: required from here prog.cc:24:20: error: no
match for 'operator-' (operand types are 'const char [4]' and
'std::vector >')
auto a = "abc" - v;
My understanding of the work flow is, in main, I say create an instance of A. Fine, the compiler then finds the template declaration for A(note that A is not a class; A<SomeType> is.). Wow, it depends on Base<int>. Fine, the compiler then finds the template declaration for Base, plugs int into the position held by T - now we have the declaration for the class Base<int>, but no definition is generated - after all, we did not provide a template for definition generation for Base<SomeType>, and no one has ever created any instance of Base<int> or has called a function on the instance. That's fine. Then the compiler extends the declaration of Base<int> and generates the declaration of A<int>. Wait, on the next line, RightFunction is called. So the compiler finds the template definition for RightFunction for A and plugs in the specific type int and generates the member function definition for A.
Since WrongFunction is never called(no specialization involved either; no explicit instantiation either), the compiler shouldn't even try to generate the code for A<int>::WrongFunction --- my question is, what the heck is going on?
Compiler: gcc 4.9.2
Thanks.
From N3337, §14.7.1/10 [temp.inst]
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. ...
So it's legal for an implementation to instantiate the virtual member function even though you never call it.
In practice, this is likely to always be the case because when instantiating a class template the compiler also needs to instantiate the vtable for that class which must be filled with the addresses of virtual member functions.

Initiating templated class without template variable [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
using a template class without a template argument
If I have a templated function, I don't need to instantiate it, since it can be inferred from the arguments, like so:
template<typename T> void MyFunc(T arg);
int x;
MyFunc(x);
Is this true for any scenario where the compiler can guess the template parameters? Specifically, I am thinking of this:
template<typename T>
class MyClass {
public:
MyClass(T) { }
};
int x;
MyClass<int> c1(x); // regular style
MyClass c2(x); // is this allowed?
Yes and no.
The compiler doesn't deduce types for class template parameters, but does allow defaults, so if you're using int quite a bit for this template, you could do:
template <typename T=int>
class MyClass {
public:
MyClass(T) {}
};
int x;
MyClass<> c2(x);
Note that this only works for one particular type per template though. It's not choosing the type based on the type of parameter you supply, just using the default you've specified for the template, is you didn't specify a type but passed (say) a double, the template above would still instantiate over int, not double.
Since the compiler can/will deduce template parameters for function templates, you can also create a small template function and use auto:
template <class T>
MyClass<T> make_MyClass(T const &v) {
return MyClass<T>(v);
}
int x;
auto c2 = make_MyClass(x);
No, it isn't allowed, as the compiler can only deduce the types during template function invocation.
That said, the common solution is a helper function.
template<typename T>
class MyClass {
public:
MyClass(T) { }
};
template<typename T>
MyClass<T> makeMyClass(T x)
{
return MyClass<T>(x);
}
No, it isn't allowed; template parameters deduction works only for template functions, template classes don't deduct template parameters from the parameters given to the constructor.