I'm working on a project in C++ and am having trouble understanding what members of a template class get explicitly instantiated when I explicitly instantiate the template class. I've written the following file, which I then compile using Visual C++ 2008 Express Edition's Release configuration and then pop into a disassembler.
template<typename T> class test {
public:
template<typename T> test(T param) {
parameter = param;
};
~test() {};
int pop();
int push();
T parameter;
};
template<typename T> int test<T>::push() {return 1;}
template<typename T> int test<T>::pop() {return 2;}
template class test<int>;
int main() {
return 0;
}
Ignoring that this file doesn't really need templates for the moment, this compiles fine. I throw the exe into the disassembler and it tells me that test<int>::pop(void), test<int>::push(void), and test<int>::~test<int>(void) are functions in the exe, but I don't see the constructor. I know I can explicitly instantiate the constructor with
template test<int>::test(int);
which causes test<int>::test<int>(int) to appear in the disassembly as a function with the other ones. My understanding of explicit instantiation is that it is supposed to tell the compiler to instantiate all members of a template class for a given set of arguments, so why is it that the constructor is not explicitly instantiated along with all the other member functions?
When the constructor is a template member function, they are not instantiated unless explicitly used.
You would see the code for the constructor if you make it a non-template member function.
template<typename T> class test {
public:
/***
template<typename T> test(T param) {
parameter = param;
};
***/
test(T param) : parameter(param) {}
~test() {}
int pop();
int push();
T parameter;
};
Related
With a class defined as follows:
template <typename T>
class A {
private:
T a;
public:
A(T& a) : a_(a) { }
template <typename D>
void Eval(D& arg)
{
// ...
}
};
template A<int>;
I want to explicitly instantiate one instance of the class, and I want this class to have one explicit instantiation of Eval. The intention here is to get a member function pointer that avoids ambiguity:
auto eval_ptr = &A<int>::Eval;
The ambiguity is not coming from anything to do with template instantiation of the class, it's caused by Eval also being a templated function.
&A<int>::Eval does not point to a function, it points to a template. And there is just no such type as a "pointer to a template".
If you want a pointer to A<int>::Eval, you need to specify D as well.
auto eval_ptr = &A<int>::Eval<int>; works just fine for example.
Addendum: Pointers-to-templates do exist in the grammatical sense, but there is no type an object can have to hold one of them. They must be immediately casted/decayed to a specific overload in order to be used, which doesn't come into play here since you want to store it in an auto.
For example: The following is fine because there's clearly only one "version" of Eval that can be meant:
void bar(void (A<int>::*arg)(int&)) {}
void foo() {
bar(&A<int>::Eval);
}
The very simple solution was specifying both template parameters:
template <typename T>
class A
{
private:
T a;
public:
A(T &a) : a_(a) {}
template <typename D>
void Eval(D &arg)
{
arg+=1;
}
};
int main()
{
auto p = &A<int>::Eval<int>;
}
I can't seem to call a method of a base class without scoping to the base class, and it seems that this is because I have overloaded the method. If I do not overload the method then the compiler doesn't complain. Here's an example of what I'd like to do:
struct BaseClass {
template <typename T> T& foo(T& t) {
return t;
}
};
class ChildClass: public BaseClass {
public:
// The presence of this template causes compiler confusion
template <class T> T& foo(T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
// But if I scope this as BaseClass::foo(...) it's all good
return foo(t);
}
};
int main() {
int t = 1;
ChildClass c;
c.bar(t);
}
If in bar(...) I call BaseClass::foo(...) the compiler does not complain, but I don't see any ambiguity here and so I'm confused as to why I'd need to do this.
When the compiler tries to match a function name with a function, it does so in two steps. In the first step it finds all the functions that match the given name. If it finds more than one function, it tries the logic of overload resolution to find the best matching function.
In the first step, if the compiler finds a name in the class, it stops looking for functions of the same name in base classes. In your case, since it finds a foo in ChildClass, it stops searching for functions named foo in BaseClass. However, the only matching foo does not match the call and the compiler reports an error.
How to resolve the problem:
Use the method you described in your post. Call BaseClass::foo(...).
Bring all the foo from BaseClass into the scope of ChildClass.
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
return sizeof(foo(1, t)); // Should work.
}
};
From the C++ standard 3.3.10 paragraph 1 :
A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class
ChildClass::foo shadows the definition of BaseClass::foo. All you need to bring it into scope is a using directive:
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl);
};
You need a using, like:
using BaseClass::foo;
I can't seem to call a method of a base class without scoping to the base class, and it seems that this is because I have overloaded the method. If I do not overload the method then the compiler doesn't complain. Here's an example of what I'd like to do:
struct BaseClass {
template <typename T> T& foo(T& t) {
return t;
}
};
class ChildClass: public BaseClass {
public:
// The presence of this template causes compiler confusion
template <class T> T& foo(T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
// But if I scope this as BaseClass::foo(...) it's all good
return foo(t);
}
};
int main() {
int t = 1;
ChildClass c;
c.bar(t);
}
If in bar(...) I call BaseClass::foo(...) the compiler does not complain, but I don't see any ambiguity here and so I'm confused as to why I'd need to do this.
When the compiler tries to match a function name with a function, it does so in two steps. In the first step it finds all the functions that match the given name. If it finds more than one function, it tries the logic of overload resolution to find the best matching function.
In the first step, if the compiler finds a name in the class, it stops looking for functions of the same name in base classes. In your case, since it finds a foo in ChildClass, it stops searching for functions named foo in BaseClass. However, the only matching foo does not match the call and the compiler reports an error.
How to resolve the problem:
Use the method you described in your post. Call BaseClass::foo(...).
Bring all the foo from BaseClass into the scope of ChildClass.
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl) {
return t;
}
template <class T> int bar(T& t) {
return sizeof(foo(1, t)); // Should work.
}
};
From the C++ standard 3.3.10 paragraph 1 :
A name can be hidden by an explicit declaration of that same name in
a nested declarative region or derived class
ChildClass::foo shadows the definition of BaseClass::foo. All you need to bring it into scope is a using directive:
class ChildClass: public BaseClass {
public:
using BaseClass::foo;
template <class T> T& foo(int baz, T& t, int szl);
};
You need a using, like:
using BaseClass::foo;
I have a templatized class like so :
template<typename T>
class A
{
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
}
I would like to add just ONE member function that would work only for 1 given type of T. Is it possible to do that at all without having to specialize the class and reimplement all the other already existing methods?
Thanks
The simplest and cleanest solution is to use a static_assert() in the body of a method, rejecting other types than the selected one (in the below example only integers are accepted):
#include <type_traits>
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
static_assert(std::is_same<T, int>::value, "Works only with ints!");
}
protected:
std::vector<T> myVector;
};
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
//f.onlyForInts(3.14f); // does not compile !
}
OK CASE DEMO
NOK CASE DEMO
This utilizes the fact that a compiler instantiates a member function of a class template only when one is actually used (not when the class template is instantiated itself). And with the above solution, when a compiler tries to do so, it fails due to the execution of a static_assert.
C++ Standard Reference:
§ 14.7.1 Implicit instantiation [temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly
instantiated. — end example ]
Yes, it's possible in C++03 with CRTP (Curiously recurring template pattern):
#include <numeric>
#include <vector>
template<typename Derived, typename T>
struct Base
{
};
template<typename Derived>
struct Base<Derived, int>
{
int Sum() const
{
return std::accumulate(static_cast<Derived const*>(this)->myVector.begin(), static_cast<Derived const*>(this)->myVector.end(), int());
}
};
template<typename T>
class A : public Base<A<T>, T>
{
friend class Base<A<T>, T>;
protected:
std::vector<T> myVector;
public:
/*
constructors + a bunch of member functions here
*/
};
int main()
{
A<int> Foo;
Foo.Sum();
}
As an alternative solution, which works also in plain C++03 (as opposed to static_assert or enable_if solutions), you may add extra defaulted template argument which will let you have both
specialized and unspecialized version of class. Then you can inherit your specialized version from the unspecialized one.
Here is a sample snippet:
#include <vector>
template<typename T, bool unspecialized = false>
class A
{
protected:
std::vector<T> myVector;
public:
void setVec(const std::vector<T>& vec) { myVector = vec; }
/*
constructors + a bunch of member functions here
*/
};
template<>
class A<int, false> : public A<int, true>
{
public:
int onlyForInt() {
return 25;
}
};
int main() {
// your code goes here
std::vector<int> vec;
A<int> a;
a.setVec(vec);
a.onlyForInt();
return 0;
}
The drawbacks of this solution is the need to add constructor forwarders, if class
has non-trivial constructors.
The static_assert technique by #PiotrS. works nicely. But it's also nice to know that you can specialize a single member function without code duplication. Just give the generic onlyForInts() an empty no-op implementation, and specialize it out-of-class for int
#include <vector>
template <typename T>
class A
{
public:
void onlyForInts(T t)
{
// no-op
}
protected:
std::vector<T> myVector;
};
template<>
void A<int>::onlyForInts(int t)
{
// works
}
int main()
{
A<int> i;
i.onlyForInts(1); // works !
A<float> f;
f.onlyForInts(3.14f); // compiles, but does nothing !
}
Live Example.
This technique comes in handy if you want to have int specific behavior without completely disabling the generic behavior.
One approach not given yet in the answers is using the standard library std::enable_if to perform SFINAE on a base class that you inherit to the main class that defines appropriate member functions.
Example code:
template<typename T, class Enable = void>
class A_base;
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>{
public:
void only_for_ints(){/* integer-based function */}
};
template<typename T>
class A_base<T, typename std::enable_if<!std::is_integral<T>::value>::type>{
public:
// maybe specialize for non-int
};
template<typename T>
class A: public A_base<T>{
protected:
std::vector<T> my_vector;
};
This approach would be better than an empty function because you are being more strict about your API and better than a static_cast because it simply won't make it to the inside of the function (it won't exist) and will give you a nice error message at compile time (GCC shows "has no member named ‘only_for_ints’" on my machine).
The downside to this method would be compile time and code bloat, but I don't think it's too hefty.
(don't you dare say that C++11 requirement is a down-side, we're in 2014 god-damnit and the next standard has even be finalized already!)
Also, I noticed, you will probably have to define my_vector in the base class instead of the final because you probably want to handle that data within the member function.
A nice way to do that without duplicating a bunch of code is to create a base base class (good god) and inherit that class in the base class.
Example:
template<typename T>
class base_data{
protected:
std::vector<T> my_vector;
};
template<typename T>
class A_base<T, typename std::enable_if<std::is_integral<T>::value>::type>: public base_bata<T>{
public:
void only_for_ints(){/* phew, finally. fiddle around with my_vector! */}
};
// non-integer A-base
template<typename T>
class A: public A_base<T>{
protected:
// helper functions not available in base
};
That does leave a horrible looking multiple-inheritance scheme, but it is very workable and makes it easy to define members based on template parameters (for future proofing).
People often don't like multiple-inheritance or how complicated/messy SFINAE looks, but I couldn't live without it now that I know of it: the speed of static code with the polymorphism of dynamic code!
Not sure where I found this, but you can use = delete; as the function definition inside the class, thereby deleting the function for the general case, and then explicitly specialize outside the class:
template <typename T>
struct A
{
auto int_only(T) -> void = delete;
};
template <> auto A<int>::int_only(int) -> void {}
int main()
{
auto a_int = A<int>{};
auto a_dbl = A<double>{};
a_int.int_only(0);
// a_dbl.int_only(3.14); error: call to deleted member function
}
https://en.cppreference.com/w/cpp/language/function#Deleted_functions
I have template class ItemContainer that actually is facade for a whole family of containers with different capabilities like sorting, indexing, grouping etc.
Implementation details are hidden in cpp. file using pimpl idiom and explicit instantiation. Template is instantiated only with well-known limited set of implementation classes that define the actual behavior of container.
Main template implements common functions supported by all containers - IsEmpty(), GetCount(), Clear() etc.
Each specific container specializes some functions that are supported only by it, e.g. Sort() for sorted container, operator[Key&] for key indexed container etc.
The reason for such design is that class is replacement for several legacy hand-made bicycle containers written by some prehistorics in early 90th. Idea is to replace old rotting implemenation with modern STL&Boost containers keeping old interface untouched as much as possible.
The problem
Such design leads to unpleasant situation when user tries to call unsupported function from some specialization. It compiles OK, but produces error on linking stage (symbol not defined).
Not very user friendly behavior.
Example:
SortedItemContainer sc;
sc.IsEmpty(); // OK
sc.Sort(); // OK
IndexedItemContainer ic;
ic.IsEmpty(); // OK
ic.Sort(); // Compiles OK, but linking fails
Of course, it could be completely avoided by using inheritance instead of specialization but I don't like to produce a lot of classes with 1-3 functions. Would like to keep original design.
Is there possibility to turn it into compile stage error instead of link stage one? I have a feeling that static assert could be used somehow.
Target compiler for this code is VS2008, so practical solution must be C++03 compatible and could use MS specific features.
But portable C++11 solutions also are welcome.
Source Code:
// ItemContainer.h
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class Impl> class ItemContainer
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
// Functions supported by sequenced specializations only
ItemPtr operator[](size_t i_index) const;
...
// Functions supported by indexed specializations only
ItemPtr operator[](const PrimaryKey& i_key) const;
...
// Functions supported by sorted specializations only
void Sort();
...
private:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
}; // class ItemContainer
// Forward declarations for pimpl classes, they are defined in ItemContainer.cpp
struct SequencedImpl;
struct IndexedImpl;
struct SortedImpl;
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SequencedImpl> SequencedItemContainer;
typedef ItemContainer<IndexedImpl> IndexedItemContainer;
typedef ItemContainer<SortedImpl> SortedItemContainer;
// ItemContainer.cpp
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementation classes definition, skipped as non-relevant
struct SequencedImpl { ... };
struct IndexedImpl { ... };
struct SortedImpl { ... };
// Explicit instantiation of members of SequencedItemContainer
template void SequencedItemContainer::Clear(); // Common
template bool SequencedItemContainer::IsEmpty() const; // Common
template ItemPtr SequencedItemContainer::operator[](size_t i_index) const; // Specific
// Explicit instantiation of members of IndexedItemContainer
template void IndexedItemContainer::Clear(); // Common
template bool IndexedItemContainer::IsEmpty() const; // Common
template ItemPtr IndexedItemContainer::operator[](const PrimaryKey& i_key) const; // Specific
// Explicit instantiation of members of SortedItemContainer
template void SortedItemContainer::Clear(); // Common
template bool SortedItemContainer::IsEmpty() const; // Common
template void SortedItemContainer::Sort(); // Specific
// Common functions are implemented as main template members
template <class Impl> bool ItemContainer<Impl>::IsEmpty() const
{
return m_data->empty(); // Just sample
}
// Specialized functions are implemented as specialized members (partial specialization)
template <> void SortedItemContaner::Sort()
{
std::sort(m_data.begin(), m_data.end(), SortFunctor()); // Just sample
}
...
// etc
If it is known at compile time that a certain function will not be implemented, then that function shouldn't have been declared in the first place. Otherwise, this is a programming error.
Having said that, you must avoid declaring such a function, or declare it such that the declaration only works if it will be implemented. That can be achieved either by a static_assert or by SFINAE.
For example
template<class Container> // you need one instantination per container supported
struct container_traits
{
static const bool has_sort; // define appropriately in instantinations
/* etc */
};
template<class container>
class ContainerWrapper {
unique_ptr<container> _m_container;
template<bool sorting> typename std::enable_if< sorting>::type
_m_sort()
{
_m_container->sort();
}
template<bool sorting> typename std::enable_if<!sorting>::type
_m_sort()
{
static_assert(0,"sort not supported");
}
public
void sort()
{
_m_sort<container_traits<container>::has_sort>();
}
/* etc */
};
Consider this example:
class A {
public:
void foo() {}
void bar();
};
Only during linking phase it could be detected an error that A::bar() is not defined and this has nothing to do with templates.
You shall define separate interfaces for your different containers and use them for your implementations. Just one of the possibilities below:
template <class Impl>
class ItemContainerImpl
{
public:
ItemContainerImpl();
protected:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
};
// No operations
template <class Impl>
class Empty : protected virtual ItemContainerImpl<Impl> {};
template <class Impl, template <class> class Access, template <class> class Extra = Empty>
class ItemContainer : public Extra<Impl>, public Access<Impl>
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
};
template <class Impl>
class SequencedSpecialization : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by sequenced specializations only
ItemPtr operator[](size_t i_index) const;
...
};
template <class Impl>
class IndexedSpecialization : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by indexed specializations only
ItemPtr operator[](const PrimaryKey& i_key) const;
...
};
template <class Impl>
class Sorted : protected virtual ItemContainerImpl<Impl> {
public:
// Functions supported by sorted specializations only
void Sort();
...
};
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SequencedImpl, SequencedSpecialization> SequencedItemContainer;
typedef ItemContainer<IndexedImpl, IndexedSpecialization> IndexedItemContainer;
typedef ItemContainer<SortedImpl, IndexedSpecialization, Sorted> SortedItemContainer;
Despite the good answers suggesting to use SFINAE, I continued to search solution that will meet my original design. And finally I found it.
The key idea is to use specialization for specific function members instead of explicit instantiation.
What was done:
Added specific functions dummy implementation for main template. Implementations containing static asserts only were placed in header file but not inlined into class definition.
Specific functions explicit instantiations were removed from .cpp file.
Specific functions specialization declarations were added to header file.
Source Code:
// ItemContainer.h
//////////////////////////////////////////////////////////////////////////////
template <class Impl> class ItemContainer
{
public:
// Common functions supported by all specializations
void Clear();
bool IsEmpty() const;
...
// Functions supported by sorted specializations only
void Sort();
...
private:
boost::scoped_ptr<Impl> m_data; ///< Internal container implementation
}; // class ItemContainer
// Dummy implementation of specialized function for main template
template <class Impl> void ItemContainer<Impl>::Sort()
{
// This function is unsupported in calling specialization
BOOST_STATIC_ASSERT(false);
}
// Forward declarations for pimpl classes,
// they are defined in ItemContainer.cpp
struct SortedImpl;
// Typedefs for specializations that are explicitly instantiated
typedef ItemContainer<SortedImpl> SortedItemContainer;
// Forward declaration of specialized function member
template<> void CSortedOrderContainer::Sort();
// ItemContainer.cpp
//////////////////////////////////////////////////////////////////////////////
// Implementation classes definition, skipped as non-relevant
struct SortedImpl { ... };
// Explicit instantiation of common members of SortedItemContainer
template void SortedItemContainer::Clear();
template bool SortedItemContainer::IsEmpty() const;
// Common functions are implemented as main template members
template <class Impl> bool ItemContainer<Impl>::IsEmpty() const
{
return m_data->empty(); // Just sample
}
// Specialized functions are implemented as specialized members
// (partial specialization)
template <> void SortedItemContaner::Sort()
{
std::sort(m_data.begin(), m_data.end(), SortFunctor()); // Just sample
}
...
// etc
This way it works at least for VS2008.
For GCC with C++11 static_assert usage requires some trick to enable lazy template function instatiation (compiled sample):
template <class T> struct X
{
void f();
};
template<class T> void X<T>::f()
{
// Could not just use static_assert(false) - it will not compile.
// sizeof(T) == 0 is calculated only on template instantiation and
// doesn't produce immediate compilation error
static_assert(sizeof(T) == 0, "Not implemented");
}
template<> void X<int>::f()
{
std::cout << "X<int>::f() called" << std::endl;
}
int main()
{
X<int> a;
a.f(); // Compiles OK
X<double> b;
b.f(); // Compilation error - Not implemented!
}
What about this ?
template <class T, class supported_types> struct vec_enabler :
boost::mpl::contains<supported_types, T> {};
// adding Sort interface
template <class T, class enabler, class Enable = void>
struct sort_cap{};
template <class T, class enabler>
struct sort_cap<T, enabler,
typename boost::enable_if< typename enabler::type >::type>
{
void Sort();
};
// adding operator[]
template <class T, class U, class R, class enabler, class Enable = void>
struct index_cap{};
template <class T, class primary_key, class ret, class enabler>
struct index_cap<T, primary_key, ret, enabler,
typename boost::enable_if< typename enabler::type >::type>
{
ret operator[](primary_key i_index) const;
};
template <class Impl>
class ItemContainer :
public sort_cap<Impl,
vec_enabler<Impl, boost::mpl::vector<A, B> > >, // sort for classes A or B
public index_cap<Impl, size_t, ItemPtr,
vec_enabler<Impl, boost::mpl::vector<C> > >, // index for class C
public index_cap<Impl, primaryKey, ItemPtr,
vec_enabler<Impl, boost::mpl::vector<B> > > // index for class B
{
public:
void Clear();
bool IsEmpty() const;
};
I find that using inheritance is the most clean way to achieve what you would like to do (which is 'adding interfaces to a class'.) Then we have the following:
int main(){
ItemContainer<A> cA;
cA.Sort();
//ItemPtr p = cA[0]; // compile time error
ItemContainer<C> cC;
//cC.Sort(); // compile time error
ItemPtr p = cC[0];
//ItemPtr pp= cC[primaryKey()]; // compile time error
}
Of course, you still are able to write the implementation in .cpp files.