Templated Member Function of Templated Class - c++

I have a templated C++ class which has a templated member function as well. The template parameters of this member function are dependent on the class's template parameters in a specific way (please see the code below).
I am instantiating (not specializing) this class for two different values of its template parameter. Everything compiles till this point. However, if I invoke the templated member function, the call for only the first instantiated object compiles and not the second one.
It appears as if the compiler is not instantiating the templated member function for the second instantiation of the template class. I am compiling the code below using "g++ filename.cpp" and am getting the following error:
filename.cpp:63: error: no matching function for call to 'Manager<(Base)1u>::init(Combination<(Base)1u, (Dependent2)0u>*)’
This is the line calling b.init(&combination_2)
g++ --version => g++ (Ubuntu/Linaro 4.4.7-1ubuntu2) 4.4.7
uname -a => Linux 3.2.0-25-generic-pae #40-Ubuntu SMP i686 i686 i386 GNU/Linux
enum Base {
AA,
BB,
CC
};
enum Dependent1 {
PP,
QQ,
RR
};
enum Dependent2 {
XX,
YY,
ZZ
};
template<Base B>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void init(T<B, D>* t);
};
template <Base B>
template <typename DependentProperty<B>::Dependent D,
template<Base,
typename DependentProperty<B>::Dependent> class T>
void Manager<B>::init(T<B, D>* t) {
t->reset();
}
int main(int argc, char** argv) {
Manager<AA> a;
Manager<BB> b;
Combination<AA, PP> combination_1;
Combination<BB, XX> combination_2;
a.init(&combination_1);
b.init(&combination_2);
return 0;
}
It is not feasible to modify the classes corresponding to Base, Dependent or Combination from my example code in our actual project. What I am really wondering is whether my syntax for defining Manager::init() is wrong, or whether there is some known property/feature/constraint of C++ or g++ that wouldn't allow this code?

The code below compiles for me, I have simplified your code a little, though it still does the same thing.
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent D; // if ever you need it
template <typename TCombinaison>
void init(TCombinaison* t)
{
t->reset();
}
};
int main(int argc, char** argv)
{
typedef Combination<AA, PP> CombinaisonA;
typedef Combination<BB, XX> CombinaisonB;
typedef DependentProperty<AA> DependencyPropertyA;
typedef DependentProperty<BB> DependencyPropertyB;
CombinaisonA combination_1;
CombinaisonB combination_2;
Manager<AA> a;
Manager<BB> b;
a.init(&combination_1);
b.init<&combination_2);
return 0;
}
EDIT: A 2nd solution so as to forbid the mixed use of combination in managers, as the OP has noticed in the comments below. Now I'm using std::is_same to check the "concept" contract.
template <Base B, typename DependentProperty<B>::Dependent D>
class Combination {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
void reset() {}
int o;
};
template <Base B>
class Manager {
public:
typedef typename DependentProperty<B>::Dependent DependencyType;
template <typename TCombinaison>
void init(TCombinaison* t)
{
static_assert(std::is_same<TCombinaison::DependencyType, Manager::DependencyType>);
t->reset();
}
};

If you combine inheritance and go away from constant template parameters, extend the Combination to provide info on its template arguments, you can get the code to compile taking into account that you don't want this to compile:
b.init(&combination_1);
You are trying very hard to specify and fix the type of the Combination for the init member template within your Manager indirectly, even though the init template will deduce it since it is the only parameter of the function, and the type si defined within main anyway.
Would you consider templating the init directly with the Combination?
This way, everything apart from the init() declaration remains the same, and your code compiles as you wanted to initially:
class Base
{
};
class AA
:
public Base
{
};
class BB
:
public Base
{
};
class Dependent1
{
};
class PP
:
public Dependent1
{};
class Dependent2
{};
class XX
:
public Dependent2
{};
template<class Base>
struct DependentProperty {
};
template<>
struct DependentProperty<AA> {
typedef Dependent1 Dependent;
};
template<>
struct DependentProperty<BB> {
typedef Dependent2 Dependent;
};
template <class Base>
class Combination {
public:
typedef Base CombinationBase;
typedef typename DependentProperty<Base>::Dependent CombinationDependent;
void reset()
{
}
int o;
};
template <class Base>
class Manager
{
public:
// Any type C
template<class C>
void init (C* t)
{
// Any type C conforming to the implicit interface holding reset()
t->reset();
// Forcing specific combination
Base b = typename C::CombinationBase();
// Forcing it again
typename DependentProperty<Base>::Dependent d = typename C::CombinationDependent();
}
};
int main(int argc, char** argv) {
Combination<AA> combination_1;
Manager<AA> a;
a.init(&combination_1);
Manager<BB> b;
Combination<BB> combination_2;
b.init(&combination_2);
b.init(&combination_1);
return 0;
}
In this case, you can extend the Combination template to provide access to its template parameters to the client code. Of course the template C in this case becomes a refinement of the Combination concept as soon as you rely on its implementation within the init member function (accessing the stored template argument values, etc).

Your code is correct, except for the function calling part.
a.init<PP, Combination>( &combination_1 );
b.init<XX, Combination> ( &combination_2 );
This compiles and runs peacefully.

The only thing I see is
template <typename DependentProperty<B>::Dependent D,
template<Base, <-- wrong
typename DependentProperty<B>::Dependent <-- wrong
> class T>
void init(T<B, D>* t);
Your class Combination waits values as a template parameter, but you want to give him types
I spent some time to fix it - like that
template <typename DependentProperty<B>::Dependent D,
template<Base BB,
typename DependentProperty<BB>::Dependent DD
> class T>
void init(T<B, D>* t);
and many other variants, but had no success.
Excuse me for arrange it as an answer, but I couldn't type so many code in a comment

Related

Trick to explicit choose overloaded method without static_cast

This is a question mainly about making the code easier on the eyes.
I have a template class t<T, Ts...> that generates an overloaded method, overloaded_method(x<T> *), for each template argument T. The argument on this method is not of the template argument type directly but for some other specialization template class, x<T>.
So, given class a and class b, we have t<a,b> which has overloaded_method(x<a> *) and overloaded_method(x<b> *).
After that I create an implementation class impl that implements x<a> and x<b>.
If I try to call overloaded_method() with an object ii of impl, the compiler doesn't know if it has to choose overloaded_method(x<a> *) or overloaded_method(x<b> *), which is understandable.
I can help the compiler by using static_cast. Eg. ti.overloaded_method(static_cast<x<a> *>(&ii)).
This works fine, but feels like a thorn in the eye, and wouldn't be nice for a user of my library. I would rather do something like ti.overloaded_method<a>(&ii), which is invalid.
Is there any way to explicitly choose which overloaded method to use, that doesn't involve static_cast and x?
template<typename T>
class x {
public:
T *v;
};
template<typename...>
class t {
public:
void overloaded_method();
};
template <typename T, typename... Ts>
class t<T, Ts...>: public t<Ts...> {
public:
void overloaded_method(x<T> *v) {
}
using t<Ts...>::overloaded_method;
};
class a
{
};
class b {
};
class impl: public x<a>,
public x<b> {
};
int
main (int argc, char *argv[])
{
t<a, b> ti;
impl ii;
ti.overloaded_method(static_cast<x<b> *>(&ii));
return 0;
}

set public/private on template function for some certain template parameter

Is it possible to make a certain template function have 2 accessibility level for some certain template parameter? (via splitting into 2 functions?)
class B{
enum ENU{
T0,T1,T2
}
template<ENU T=T0> someType f(){ ... } //want T1,T2 = public, T0 = private
};
Current usage (the solution should not change it):-
B b;
int aa=b.f<T0>(); //should fail
std::string bb=b.f<T1>();// should ok
Edit: B has a lot of functions like this.
Here is the full code (just in case someone want to edit or use) https://ideone.com/ryNCml.
I doubt what you are trying to do is possible, as specializing functions on a value ain't allowed in C++.
Though if you don't need enumerations, you could write something similar:
class B {
public:
struct T0{};
struct T1{};
struct T2{};
template<typename T> void f(T, ...) {
static_assert(std::is_same_v<T, T1> || std::is_same_v<T, T2>);
}
private:
void f(T0, ...) {}
};
int main(int argc, char **argv) {
B b{};
b.f(T1{}); // Should compile
b.f(T0{}); // Should not compile
}
If you would use the same function implementation, you can either forward this to a common method, or simply put T0 private.
Alternatively, you could make use of a proxy object which could convert the value, though I'm not sure if this is standard C++ of an extension of the compiler I'm familiar with:
class B {
public:
enum class T { //< Strong typed!
T0,
T1,
T2
}
template <T t>
struct TWrapper {};
template <T ActualT>
void f(..., TWrapper<ActualT> tw = TWrapper<ActualT>{});
private:
template <>
struct TWrapper<T0> {};
}
As far as I can understand, you want to forbid the use of T0 as a template parameter while invoking member method f.
To do that, you can use either std::enable_if or a static_assert.
It follows a minimal, working example:
#include<type_traits>
class B {
public:
enum ENU { T0,T1,T2 };
template<ENU T>
std::enable_if_t<(T==T1||T==T2),int>
f() { return 42; }
template<ENU T>
int g(){
static_assert(T==T1||T==T2, "not allowed");
return 42;
}
};
int main() {
B b;
b.f<B::T1>();
// It doesn't work
//b.f<B::T0>();
b.g<B::T1>();
// It doesn't work
//b.g<B::T0>();
}
Given you want to support only a finite set of template arguments, I would write three functions which are not template functions, and give them the right visibility. Then make them delegate to a private template function which does the work. This would look like:
class B{
public:
enum ENU{
T0,T1,T2
}
private:
template<ENU T=T0> int f(){
std::cout<<"In enum "<<T<<std::endl;
return 0;
}
protected:
someType fT0() { return f<T0>(); }
public:
someType fT1() { return f<T1>(); }
someType fT2() { return f<T2>(); }
};
Contrary to your requirements, the usage changes - but this is often the simplest approach:
B b;
int aa=b.fT0(); // fails
int bb=b.fT1();// ok
Alternatively, you can make the template be public, but give it a dummy argument (with a default), and make the type of the dummy argument depend on the template parameter (via traits). If the type of the dummy is a private class, the template will only be callable by a member.
template <ENU T>
struct protection_traits;
class B{
friend class protection_traits<T0>; // So it has access to Protected.
protected:
struct Protected{};
public:
struct Public{};
enum ENU{
T0,T1,T2
}
template<ENU T=T0> int f( typename protection_traits<T>::type = {})
{ std::cout<<"In enum "<<T<<std::endl; }
};
template <ENU T>
struct protection_traits
{
typedef B::Public type; // Default to public
};
template<>
struct protection_traits<T0>
{
typedef B::Protected type; // But T0 uses Protected
};
Usage:
B b;
int aa=b.f<T0>(); // fails (no access to B::Protected)
int bb=b.f<T1>(); // ok
Note: This latter solution hasn't been fed to a compiler. There will be typos.

Full class template specialization with forward declarations

It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.

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-function -> passing a template-class as template-argument

i try to make intensive use of templates to wrap a factory class:
The wrapping class (i.e. classA) gets the wrapped class (i.e. classB) via an template-argument to provide 'pluggability'.
Additionally i have to provide an inner-class (innerA) that inherits from the wrapped inner-class (innerB).
The problem is the following error-message of the g++ "gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)":
sebastian#tecuhtli:~/Development/cppExercises/functionTemplate$ g++ -o test test.cpp
test.cpp: In static member function ‘static classA<A>::innerA<iB>* classA<A>::createInnerAs(iB&) [with iB = int, A = classB]’:
test.cpp:39: instantiated from here
test.cpp:32: error: dependent-name ‘classA::innerA<>’ is parsed as a non-type, but instantiation yields a type
test.cpp:32: note: say ‘typename classA::innerA<>’ if a type is meant
As you can see in the definition of method createInnerBs, i intend to pass a non-type argument. So the use of typename is wrong!
The code of test.cpp is below:
class classB{
public:
template < class iB>
class innerB{
iB& ib;
innerB(iB& b)
:ib(b){}
};
template<template <class> class classShell, class iB>
static classShell<iB>* createInnerBs(iB& b){
// this function creates instances of innerB and its subclasses,
// because B holds a certain allocator
return new classShell<iB>(b);
}
};
template<class A>
class classA{
// intention of this class is meant to be a pluggable interface
// using templates for compile-time checking
public:
template <class iB>
class innerA: A::template innerB<iB>{
innerA(iB& b)
:A::template innerB<iB>(b){}
};
template<class iB>
static inline innerA<iB>* createInnerAs(iB& b){
return A::createInnerBs<classA<A>::template innerA<> >(b); // line 32: error occurs here
}
};
typedef classA<classB> usable;
int main (int argc, char* argv[]){
int a = 5;
usable::innerA<int>* myVar = usable::createInnerAs(a);
return 0;
}
Please help me, i have been faced to this problem for several days.
Is it just impossible, what i'm trying to do? Or did i forgot something?
Thanks, Sema
Line 32 should read:
return A::template createInnerBs<innerA>(b);
since createInnerBs is dependent on the template parameter A.
You'll also need to make the constructors of innerA and innerB public.
Here is the corrected code which compiles for me:
class classB{
public:
template < class iB>
class innerB{
iB& ib;
public:
innerB(iB& b)
:ib(b){}
};
template<template <class> class classShell, class iB>
static classShell<iB>* createInnerBs(iB& b){
// this function creates instances of innerB and its subclasses,
// because B holds a certain allocator
return new classShell<iB>(b);
}
};
template<class A>
class classA{
// intention of this class is meant to be a pluggable interface
// using templates for compile-time checking
public:
template <class iB>
class innerA: public A::template innerB<iB>{
public:
innerA(iB& b)
: A::template innerB<iB>(b){}
};
template<class iB>
static inline innerA<iB>* createInnerAs(iB& b);
};
template<class A>
template<class iB>
inline classA<A>::innerA<iB>* classA<A>::createInnerAs(iB& b)
{
return A::template createInnerBs<classA::template innerA>(b);
}
typedef classA<classB> usable;
int main (int argc, char* argv[]){
int a = 5;
usable::innerA<int>* myVar = usable::createInnerAs(a);
return 0;
}
Even if I think you're overcomplicating things... But I don't fully understand your use case.