I am still learning C++ hard and have now generated a circular dependency that, according to C2039: Class is not a member of Namespace may be the cause to my issue that I get a C2039 error. Can somebody help me how to cut this circle?
I have two template classes and the template class tXmlGeometry<Part> has a member function that shall declare an instance of template class tXmlStraightLine. Both are inside namespace nXml but the compiler complains that tXmlStraightLine is not member of nXml.
I have to say that I bound the tXmlGeometry.h into the tXmlStraightLine header but I get an error when I try to bind the tXmlStraightLine.h into the tXmlGeometry header at the same time. I also just tried to remove the #include nXml/tXmlGeometry from the tXmlStraightLine header to no avail.
So here's a simplified code for the tXmlGeometry template class inside namespace nXml:
namespace nXml
{
template<class Part>
class tXmlGeometry : public tXmlNode<Part>
{
public:
tXmlGeometry(Part* part);
~tXmlGeometry();
void AddStraightLine2D(const pugi::xml_node& node) {};
};
}
;
and the implementation of the AddStraightLine2D method that causes the issue:
template<class Part>
inline void nXml::tXmlGeometry<Part>::AddStraightLine2D(const pugi::xml_node& this_node)
{
nXml::tXmlStraightLine<Part> straightline_xml(this);
//do more stuff
}
Here's the simplified code for the tXmlStraightLine template class:
namespace nXml
{
template<class Part>
class tXmlStraightLine : public tXmlSegment2D<Part>
{
public:
tXmlStraightLine(tXmlGeometry<Part>* geo, const int npos);
~tXmlStraightLine();
}
;
}
;
Can somebody advice me how to avoid that circular dependency?
EDIT: I corrected an error in member function naming.
Since they're both template classes, I'd consider placing them in the same header.
In order to avoid dependency issues, you can separate the declarations and definitions. Something like this:
namespace nXml
{
// tXmlGeometry<Part> declaration
template<class Part>
class tXmlGeometry : public tXmlNode<Part>
{
public:
tXmlGeometry(Part* part);
~tXmlGeometry();
inline void AddStraightLine2D(const pugi::xml_node& this_node);
};
// tXmlStraightLine declaration
template<class Part>
class tXmlStraightLine : public tXmlSegment2D<Part>
{
public:
tXmlStraightLine(tXmlGeometry<Part>* geo, const int npos);
~tXmlStraightLine();
};
// tXmlGeometry<Part> definitions
template<class Part>
inline void nXml::tXmlGeometry<Part>::AddStraightLine2D(const pugi::xml_node& this_node)
{
nXml::tXmlStraightLine<Part> straightline_xml(this);
//do more stuff
}
}
;
Related
I have an application class that can take in a dependent class as a template argument to the constructor. This dependent class is required to provide certain templated functions that the application class can call. I would like to offload this dependent class object to a pimpl class so the application class is not a template class and thus header-only.
Here is a rough idea of what I mean.
///////////
// impl.h
///////////
template<typename Helper>
struct Impl
{
public:
Impl(Helper& helper) : helper_(helper)
{
}
template <typename T>
void someHelperFn1(T t)
{
helper_->fn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return helper_->fn2();
}
private:
Helper& helper_;
};
///////////
// app.h
///////////
#include "impl.h"
class App
{
public:
template<typename Helper>
App(Helper &h) :impl_(new Impl) {}
template <typename T>
void someHelperFn1(T t)
{
impl_->someHelperFn1(t);
}
template <typename U>
SomeOtherClass<U> someHelperFn2()
{
return impl_->someHelperFn2();
}
void someAppFn();
private;
std::unique_ptr<Impl> impl_;
};
///////////
// app.cpp
///////////
void App::someAppFn()
{
// some useful code
}
I realize the above code doesn't compile since Impl is really a template class and so App would also be a template class too. That is what I would like to avoid so that App is not a header-only class. I found something similar except the functions that I want to call from the helper dependency are template functions and they are not in this case. It seemed pretty close otherwise to what I wanted to do.
Any ideas on how I can avoid making App a template class?
I tried making the helper class use a common base class but that is not really possible with the template functions.
Also, note that I am limited to C++ 17 for the compiler.
You will need to make sure the public header file (the one with the class that has the pimpl pointer) doesn't expose the header file only class template of the implementation. Use an interface for that like this.
I did not dependency inject the implementation because that should not be needed.
#include <memory>
#include <iostream>
// public header file
// for pimpl pattern I often use an interface
// (also useful for unit testing later)
class PublicItf
{
public:
virtual void do_something() = 0;
virtual ~PublicItf() = default;
protected:
PublicItf() = default;
};
// the public class implements this interface
// and the pimpl pointer points to the same interface
// added advantage you will have compile time checking that
// the impl class will all the methods too.
class PublicClass final :
public PublicItf
{
public:
PublicClass();
virtual ~PublicClass() = default;
void do_something() override;
private:
std::unique_ptr<PublicItf> m_pimpl; // the interface decouples from the template implementation (header file only)
};
// private header file
// this can now be a template
template<typename type_t>
class ImplClass final :
public PublicItf
{
public:
void do_something() override
{
m_value++;
std::cout << m_value << "\n";
}
private:
type_t m_value{};
};
// C++ file for Public class
// inlcude public header and impl header (template)
PublicClass::PublicClass() :
m_pimpl{ std::make_unique<ImplClass<int>>() }
{
};
void PublicClass::do_something()
{
m_pimpl->do_something();
}
// main C++ file
int main()
{
PublicClass obj;
obj.do_something();
return 0;
}
Playing with C++ 20 modules, I have the following snippet:
export {
template<class T>
class Suite {
private:
std::vector<ConcreteBuilder<T>> things {};
};
template <class T>
class ConcreteBuilder : Builder<T> {
private:
// A collection of things of function pointers or functors
std::vector<std::function<void()>> things;
public:
// Virtual destructor
virtual ~TestBuilder() override {};
// Add a new thing to the collection of things
template<typename Function>
void add(Function&& fn) {
tests.push_back(std::forward<Function>(fn));
}
// override the build() base method from Builder<T>
virtual T build() const override {
return this->things;
}
};
}
And I am getting this Clang error:
error: use of undeclared identifier 'ConcreteBuilder'
std::vector<ConcreteBuilder> things {};
Why I can't access to a type that are in the same module at the same level?
The compiler compiles the file from the top down, not all at once. It is hitting the definition of std::vector<ConcreteBuilder<T>> before it gets to the definition of class ConcreteBuilder.
So, you need to move your definition of Suite after the definition of ConcreteBuilder, so the compiler knows what it is when you use it in the vector definition.
namespace N
{
template<typename tname> class C
{
public:
friend void f(int, C<tname>);
};
}
template<typename tname>
void N::f(int, N::C<tname>)
{
}
I am creating a friend function f like above but the compiler informed me this error :
'f': is not a member of N.
Meanwhile, without the namespace, my code will run correcly.
My code will be correct too when I use normal class instead of generic class (no remove namespace).
And it will also have no error with fully declaration. Like following code:
namespace N
{
template<typename tname> class C
{
public:
friend void f(int, C<tname>)
{
//mycode
}
};
}
Could someone help me fix this error in my first code? Thank you very much.
The friend declaration does not mean that the function is now a member of that class. It only means that f has access to the private members of C.
So if f is in the global namespace it cannot be referenced as being inside namespace N with N::f, it is still only a ::f, even after the friend declaration.
In the second example you're declaring f as a member function and declaring it a friend which I'm not sure serves a purpose.
The following compiles:
namespace N
{
template<typename tname>
class C;
template<typename tname>
void f(int, C<tname>);
template<typename tname> class C
{
public:
friend void f(int, C<tname>);
};
}
template<typename tname>
void N::f(int, N::C<tname>)
{
}
int main()
{
}
I have the following piece of code, which doesn't compile (the compiler complains that B::fn is inaccessible).
#include <iostream>
using namespace std;
template<typename T>
class B
{
public:
void fn(T &&obj)
{
cout<<"base version\n";
}
};
template<typename T>
class A : public B<T>
{
private:
using B<T>::fn;
public:
void fn(const T &obj)
{
cout<<"derived version\n";
}
};
int main()
{
A<int *> a;
a.fn(new int(5));
}
To make the code work, it seems that I can
define a separate void fn(T &&obj), in the derived class, or,
make the inheritance private and do away with the access specifier
Could anyone please explain why my current code doesn't work, but the above approaches do?
[UPDATE]: I undersand that B::fn would be private. The reason I'm confused is that class A : private B<T> fixes the problem.
with:
private:
using B<T>::fn;
B<T>::fn is visible, but private.
replace by public and it would also be public.
If you remove the using B<T>::fn;, the B<T>::fn is hidden by A::fn,
so the call in main calls A::fn.
I am currently having an issue with templated methods. I have this public class implementing a template method:
namespace Private { class InternalClass; }
namespace Public
{
class PublicClass
{
public:
PublicClass();
virtual ~PublicClass();
template<class T>
bool Add(bool primary);
private:
Private::InternalClass* _pInternal;
};
template<class T>
bool PublicClass::Add(bool primary) { return _pInternal->Add<T>(primary); }
}
The internal class is implemented that way:
namespace Private
{
class InternalClass
{
public:
InternalClass();
virtual ~InternalClass();
template <class T>
bool Add(bool primary);
};
template<class T>
bool InternalClass::Add(bool primary) { return false; }
}
As this internal class header won't be available with the provided sources, I must class forward it within the PublicClass header and I add the include to PrivateClass.h inside the PublicClass.cpp file.
1) Any idea why I would be getting the following error:
error : member access into incomplete type 'Private::InternalClass' / note: forward >declaration of 'Private::InternalClass'
2) What would be the best way of hiding my PublicClass::Add() implementation?
UPDATED
Reason for error at 1) is because of this as stated by Cornstalks.
For 2), how can I hide my implementation without including PrivateClass.h within the PublicClass header file?
You have encountered a very interesting problem - you want to implement the PImpl idiom where the privately implemented class has a template method. Well, this can be solved, meaning you CAN hide the template's implementation, but only when you know which types will be used to instantiate your Add<T> method in your program.
Say, your template will work only with types AClass and BClass. Then you can split your files as follows (comments are inlined):
File public.h:
#ifndef PUBLIC_H
#define PUBLIC_H
// Forward declaration ! It's sufficient in this case !
namespace Private { class InternalClass; }
// Declare all classes your Add<T> method should work with
struct AClass {};
struct BClass {};
namespace Public
{
class PublicClass
{
public:
PublicClass() {}
virtual ~PublicClass() {}
template <typename T>
bool Add(bool primary); // DO NOT implement this method, just declare
private:
Private::InternalClass* _pInternal;
};
// "Explicit instantiation declarations", for each type the method will work with:
extern template bool PublicClass::Add<AClass>(bool primary);
extern template bool PublicClass::Add<BClass>(bool primary);
}
#endif
File public.cpp:
#include "public.h"
// NOTE: this is hidden in CPP file, noone will see your implementation
namespace Private
{
class InternalClass
{
public:
InternalClass() {}
virtual ~InternalClass() {}
template <typename T>
bool Add(bool primary);
};
// Magic! Here is the actual implementation of your private method
template <typename T>
bool InternalClass::Add(bool primary)
{
return false;
}
}
namespace Public
{
// Original definition moved to CPP file !
template <typename T>
bool PublicClass::Add(bool primary)
{
return _pInternal->Add<T>(primary);
}
// And again list the allowed types, this time using "explicit instantiation definitions"
template bool PublicClass::Add<AClass>(bool primary);
template bool PublicClass::Add<BClass>(bool primary);
}
File main.cpp:
#include "public.h"
int main()
{
Public::PublicClass pc;
pc.Add<AClass>(true); // works !
pc.Add<BClass>(false); // works !
// pc.Add<int>(true); linker error as expected,
// becuase there is no explicit instantiation for Add<int>
return 0;
}