Explicit instantiation of template class with templated member functions - c++

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>;
}

Related

Class template explicit instantiation declaration

This is a bit of a complicated pattern that doesn't fit well with friendship. Maybe I have to reconsider the design, but for now I'm just interested whether it is possible to make this work. The problem is that I can't declare class A template explicit instantiation (with incomplete class B as a template argument) that I want to use in a function specialization declaration that I want to use as a friend declaration in the definition of B.
namespace ns
{
template<class ElemT>
void assem_elem(ElemT& elem);
template<class CompT>
class ElemTempl
{
public:
ElemTempl()
{
assem_elem(*this);
}
CompT comp;
};
namespace el { class Comp; }
template class ElemTempl<el::Comp>; // error: 'ns::ElemTempl<ns::el::Comp>::comp' uses undefined class 'ns::el::Comp'
using Elem = ElemTempl<el::Comp>;
template<> void assem_elem<Elem>(Elem& elem);
namespace el
{
class Comp
{
friend void ns::assem_elem<Elem>(Elem& elem);
void link(){}
};
}
template<> void assem_elem<Elem>(Elem& elem)
{
elem.comp.link();
}
}
int main()
{
ns::Elem el{};
return 0;
}
Update:
I came up with two solutions. First, I can just remove
template class ElemTempl<el::Comp>;
line at all. The next line
using Elem = ElemTempl<el::Comp>;
seems to be a declaration of the instantiation(?). Also, even without using line I can write
template<> void assem_elem<ElemTempl<el::Comp>>(ElemTempl<el::Comp>& elem);
directly and this will work. But why? I can't do this with regular classes. At least I must say something like <class RegularClass>, not just <RegularClass>.
The second solution is using a class and passing it through the element's template parameters:
namespace ns
{
template<class CompT, class AssemT>
class ElemTempl
{
public:
ElemTempl()
{
AssemT{ *this };
}
CompT comp;
};
class Assem;
namespace el
{
class Comp
{
friend ns::Assem;
void link() {}
};
}
using Elem = ElemTempl<el::Comp, Assem>;
class Assem
{
public:
Assem(Elem& elem) { elem.comp.link(); }
};
}
But here is also some thing that needs clarification. Class Assem uses Elem, thus it instantiates Elem, but Elem needs Assem to be instantiated and Assem is not defined yet. How can this work?
You seems to confound explicit instantiation and template specialization.
With template class ElemTempl<el::Comp>; (explicit instantiation), you instantiate the full class, and CompT comp; requires a complete type, whereas el::Comp is just forward declared.
using Elem = ElemTempl<el::Comp>; is just the definition of an alias. no instantiation done.
template<> void assem_elem<Elem>(Elem& elem); declares a specialization, Elem might be incomplete.
Class Assem uses Elem, thus it instantiates Elem, but Elem needs Assem to be instantiated and Assem is not defined yet. How can this work?
Elem by itself only need forward declaration to be valid.
The class requires complete type el::Comp when instantiated.
The constructor ElemTempl::ElemTempl requires complete Assem when instantiated.
Constructors and methods are not instantiated when class is implicitly instantiated, but they are when the class is explicitly instantiated.

Calling parent class method of template class with different signature but same name doesn't work [duplicate]

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;

Why must I scope an overloaded template base class method?

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;

Partial Specialization of Operator()

One of my classes declares a templated function:
template<class A, class B>
A do_something(const std::vector<B> &data)
which I'd like to partially specialize on typename A. B is a family of types that implement a pretty minimal interface, and we use a lot of them, so I'd like my specialization to be generic on B. I suspect this is doubly vexing as typename A is used only as the return type.
From the internet, I've gleaned that I can't partially specialize a function, so I've created a class as follows:
template<class A, class B>
class do_something_implementation {
public:
do_something_implementation(const std::vector<B> &data_) {
data = data_;
}
int do_something_implementation<int, B>::operator()() {
/* Complicated algorithm goes here... */
}
double do_something_implementation<double, B>::operator()() {
/* Different complicated algorithm goes here... */
}
private:
std::vector<B> data;
}
When I try to compile that (using Visual Studio 2008), the compiler crashes (!) and I get the following error:
fatal error C1001: An internal error has occurred in the compiler.
I assume this is my problem and not the compiler's. Is there a better way to express the partial specialization I'm aiming for?
Usually, it goes like this:
template <typename A, typename B>
struct DoSomethingHelper
{
static A doIt(const std::vector<B> &data);
};
template <typename B>
struct DoSomethingHelper<double, B>
{
static double doIt(const std::vector<B> &data) { ... }
};
template <typename B>
struct DoSomethingHelper<int, B>
{
static int doIt(const std::vector<B> &data) { ... }
};
template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }
Now that you've seen the classic forward to static method, there is actually another way when the type for which to specialize is "complete".
You may not be able to partially specialize a function, but you can perfectly overload it.
template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }
template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }
template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }
template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }
The trick is to pass an "unused" argument to doImpl for the sole purpose of actually selecting the right implementation (thanks to overload resolution).
Here I simply chose to pass (A*)0, because this does not involve A's constructor (in case it's non trivial).
This dispatch idiom is what is used in the STL to implement some algorithm with better efficiency for some iterator categories (for example, std::distance is O(1) for random iterators).
I find it much more lightweight that using a helper class with static methods and partial specializations... but maybe that's just me :)
People typically just forward to a static implementation.
template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
static A do_something(class_type* not_this, const std::vector<B>& data) {
//...
}
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
return X<A, B>::do_something(this, data);
};
Not a solution to your problem (there are a couple already there), but some of the things that are wrong in your code:
You are missing a struct or class keyword in the template class declaration:
template <typename A, typename B> struct do_something_implementation {
// ^^^^^^
Inside the class definition, member functions must not use a qualified name, regardless of whether the class is a template or not:
class A {
void A::foo() {} // Error, should be: void foo() {}
};
Member template specializations cannot appear inside the class definition, but at the namespace level:
class B {
template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}
Plus on your case, the member function is not a template, but rather a non-templated member function (the template is the containing class, not the function itself). What your code is effectively trying to do is defining other class' member functions inside the general template, kind of trying to do.
Overall there was enough errors to make parsing the code almost impossible for the compiler to identify what you were trying to do and provide a good error message, but still, it should have provided any error message pointing to the first line that you copied instead of chocking to death.

C++ template arguments in constructor

Why doesn't this code compile?
template <class T>
class A
{
public:
A(T t) : t_(t) {}
private:
T t_;
};
int main()
{
A a(5.5);
// A<double> a(5.5); // that's what i don't want to do
}
I want template arguments to be implicit.
Like in this example:
template<class T>
T Foo(T t) { return t; }
// usage:
Foo(5.5);
UPDATE: named-constructor idiom isn't acceptable for me. I want to use this class for RAII.
The only way to do so is const A& a = A::MakeA(t), but it's ugly!
Since you have to name the type of a variable (C++03 can't infer the type of a variable), you can only do:
A<double> a(5.5); // that's what i don't want to do
The situation is a little easier when you needn't make a variable of the type, but want to pass it to some other function. In this case, you define an auxiliary "constructor function" (see std::make_pair):
template <class T>
A<T> make_a(T t) { return A<T>(t); }
and then use it like this:
another_function(make_a(1.1));
In C++0x, you will be able to do even
auto a(make_a(5.5));
to define your variable a.
However, inferring A's argument from its constructor is generally impossible, because you can't tell which specializations have the conversion constructor from a given type. Imagine there's a specialization
template <>
struct A<void>
{
A(double);
};