I am writing a class C which has an inner class T, and I'd like the details of T hidden as an internal implementation of C. Methods in C are all using pointers to T. This is of course possible as:
// In header
class C {
public:
class T;
T* f();
void g(T*);
};
// In .cpp
class C::T { /* details here */ };
Now my question is, how can I define C::T as a type alias of another one, in .cpp file. The following doesn't compile at all, but it illustrates what I want to do:
// Outside the class C
using C::T = std::string;
Is there any workaround to this, while maintaining the goal, i.e. hide the detail of C::T?
As others pointed out, it cannot be done. This is my suggestion:
// .h
class C {
public:
struct T;
T* f();
void g(T*);
};
// .cpp
struct C::T
{
IMPL_TYPE data;
//If one is carefull with lifetimes this can almost in any context act as IMPL_TYPE.
//And if necessary, the data member can be accessed.
operator IMPL_TYPE&(){return data};
}
You cannot, because the forward declaration class T; within class C declares a class type whose True Name is C::T, and is therefore not identical to the type whose True Name is std::basic_string<...>.
You might consider the following:
// C.h
#include "internal/T.h"
namespace foo {
class C {
public:
using T = internal::T;
// ...
};
}
// internal/T.h
namespace foo { namespace internal {
using T = std::string;
}}
The closest you can come to this would be to have your t derive from string:
class C::T : public std::string { ... };
T can never be truly hidden or redefined to be a type alias in a different .cpp file.
The following round about method should work for your needs.
class C
{
public:
// Use a base class for just the pointers.
struct TBase
{
virtual ~TBase() {}
};
TBase* f();
void g(TBase*);
// Allow client code to define a concrete type using a template parameter.
template <typename Data> struct T : TBase
{
Data data;
};
};
Then, in a .cpp file, use:
using Type = C::T<std::string>;
Type* obj = new Type;
obj->data = "Some string";
C c;
c.g(obj);
TBase* ptr = c.f();
Related
I want to make a class one that can build up class two by func1.
I have two type of class overloading. The primary template class, and the overloading template specialization class.
Primary class one is fine. But class one<void> can not implement func1.
The compiler complains return type 'class two<void>' is incomplete, aggregate 'two<void> t' has incomplete type and cannot be defined, and two<void> used in a nested specifier, stdx::shared_future<void>::num_copies_ = 2;.
What can I do to make a one version of func1?
Thank you.
template<class T2>
class two;
template<>
class two<void>;
template<class T1>
class one
{
// ...
public:
two<T1> func1()
{
two<T1> t;
two<T1>::two__ = 1;
//...
// manipulation of obj t.
//...
return t;
}
// ...
};
template<>
class one<void>
{
// ...
public:
two<void> func1()
{
two<void> t;
two<void>::two__ = 1;
//...
// manipulation of obj t.
//...
return t;
}
// ...
};
template<class T2>
class two
{
static int two__;
// definition of two
};
template<>
class two<void>
{
public:
static int two__;
// definition of two<void>
};
To avoid errors related to incomplete types the one::func1 method can be defined after two. It can be declared like this:
template<>
class one<void> {
public:
two<void> func1();
};
And then, after two has been defined:
two<void> one<void>::func1() {
// ...
}
I imitated the std::enable_shared_from_this to create a template class, but I made the class use the type definition in its subclass.
Unfortunately!
Although I used typename, after compiling,
//
// https://ideone.com/eYCBHW http://ideone.com/eYCBHW
#include <iostream>
#include <set>
#include <map>
using namespace std;
template<class _S> struct A {
};
template<class _Subclass>
class Global {
public:
typedef typename _Subclass::connection_t connection_t;
//std::map<std::string, _Subclass::connection_t> connections;
//std::set<_Subclass::connection_t> connections;
//using typename _Subclass::connection_t;
//typename _Subclass::connection_t* connections;
//connection_t* connections;
};
class CConnection {};
class SConnection;
class Client : public Global<Client> {
public:
typedef CConnection connection_t;
};
#if 0
class Server : public Global<Server> {
public:
typedef SConnection connection_t;
};
#endif
class SConnection {};
int main() {
// your code goes here
return 0;
}
GCC complained:
prog.cpp: In instantiation of ‘class Global<Client>’:
prog.cpp:25:23: required from here
prog.cpp:14:43: error: invalid use of incomplete type ‘class Client’
typedef typename _Subclass::connection_t connection_t;
^~~~~~~~~~~~
prog.cpp:25:7: note: forward declaration of ‘class Client’
class Client : public Global<Client> {
^~~~~~
How to solve it?
References
Where and why do I have to put the “template” and “typename” keywords?
C++ - meaning of a statement combining typedef and typename [duplicate]
Two template classes use each other as template argument
Having a typedef at class level requires the template arguments to be complete types. How would the compiler otherwise be able to check, if the type provided as argument actually has some equivalent typedef itself?
Analogously, the following is going to fail:
class C;
using G = Global<C>; // C is not a complete type!
class C // too late...
{
// ...
};
Problem with curiously recurring template pattern, which is what you're trying to implement, that at the point you try to derive, the class is not yet complete, just as in my example above:
class Client : public Global<Client> // client is not yet complete!
{
}; // only HERE, it will get complete, but that's too late for above
Ever wondered, though, why member variables are known within member functions even though being declared after the function? That's because
class C
{
void f() { n = 12; }
int n = 10;
};
is compiled as if it was written as:
class C
{
inline void f();
int n = 10;
};
void C::f() { n = 12; } // n is known now!
This is at the same time the clue where you can use the template argument the way you intend:
template<class T> // different name used! *)
class Global
{
public:
void f()
{
typedef typename T::connection_t connection_t; // possible here!
// (similar to why you can use the static cast as in the link provided)
}
};
That won't help, though, with your members:
std::map<std::string, typename T::connection_t> connections;
// ^ additionally was missing, but won't help either
T still remains incomplete at this point.
Within the comments, though, you only seem to use the connection type. If you don't need the client or server class for any reason other than the typedef, you can solve the issue pretty simply:
template<class T> // different name used! *)
class Global
{
std::map<std::string, T> connections;
// ^ use T directly
};
class Client : public Global<CConnection>
// ^ make sure it is defined BEFORE
{
// ...
};
Otherwise, you need to fall back to other means, e. g. the pimpl pattern, where you would let the implementation class inherit from the template.
*) Identifiers starting with underscore followed by captial letter, as well as those containing two subsequent identifiers, are reserved for the implementation (i. e. for use by the compiler). Defining your own such ones yields undefined behaviour.
Edit (stolen from the comments):
If you need client or server from within Global, you could provide both as separate template paramters as well:
template <typename Base, typename Connection>
{
// use Connection directly, e. g. for member definitions
// and Base within member functions as mandated by CRTP
};
class Client : public Global<Client, CConnection>
{ /* ... */ };
I've encountered a header in an external sdk like so:
// external.h
//
template <class T> class MyBaseEnum
{
public:
/** String list. */
static const char *mStrings[];
//! Constructor.
inline MyBaseEnum(){}
//! Destructor.
inline ~MyBaseEnum()
{
}
};
I've seen this class used in the same sdk in another header like so:
// foo.h
//
class Foo
{
enum MyEnum
{
A = 0,
B,
C
};
typedef MyBaseEnum< MyEnum > MyEnumType;
MyEnumType bar;
};
I don't have access to the corresponding cpp file to see how mStrings is initialized for bar, but I think this is related to type traits.
What would the syntax look like in foo.cpp to correctly initialize MyEnumType::mStrings?
As MyBaseEnum is a templated class, the mStrings member can't be defined in a separate source file. It has to be done in a header file that is included, as the definition requires the template argument.
The syntax is basically the same as defining any other string array:
template<class T>
const char* MyBaseEnum<T>::mStrings = { ... };
I am trying to use the pimpl pattern and define the implementation class in an anonymous namespace. Is this possible in C++? My failed attempt is described below.
Is it possible to fix this without moving the implementation into a namespace with a name (or the global one)?
class MyCalculatorImplementation;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
MyCalculatorImplementation* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
No, the type must be at least declared before the pointer type can be used, and putting anonymous namespace in the header won't really work. But why would you want to do that, anyway? If you really really want to hide the implementation class, make it a private inner class, i.e.
// .hpp
struct Foo {
Foo();
// ...
private:
struct FooImpl;
boost::scoped_ptr<FooImpl> pimpl;
};
// .cpp
struct Foo::FooImpl {
FooImpl();
// ...
};
Foo::Foo() : pimpl(new FooImpl) { }
Yes. There is a work around for this. Declare the pointer in the header file as void*, then use a reinterpret cast inside your implementation file.
Note: Whether this is a desirable work-around is another question altogether. As is often said, I will leave that as an exercise for the reader.
See a sample implementation below:
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
void* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
MyCalaculator::~MyCalaculator()
{
// don't forget to cast back for destruction!
delete reinterpret_cast<MyCalculatorImplementation*>(pimpl);
}
int MyCalculator::CalculateStuff(int x)
{
return reinterpret_cast<MyCalculatorImplementation*>(pimpl)->Calculate(x);
}
No, you can't do that. You have to forward-declare the Pimpl class:
class MyCalculatorImplementation;
and that declares the class. If you then put the definition into the unnamed namespace, you are creating another class (anonymous namespace)::MyCalculatorImplementation, which has nothing to do with ::MyCalculatorImplementation.
If this was any other namespace NS, you could amend the forward-declaration to include the namespace:
namespace NS {
class MyCalculatorImplementation;
}
but the unnamed namespace, being as magic as it is, will resolve to something else when that header is included into other translation units (you'd be declaring a new class whenever you include that header into another translation unit).
But use of the anonymous namespace is not needed here: the class declaration may be public, but the definition, being in the implementation file, is only visible to code in the implementation file.
If you actually want a forward declared class name in your header file and the implementation in an anonymous namespace in the module file, then make the declared class an interface:
// header
class MyCalculatorInterface;
class MyCalculator{
...
MyCalculatorInterface* pimpl;
};
//module
class MyCalculatorInterface{
public:
virtual int Calculate(int) = 0;
};
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
namespace {
class MyCalculatorImplementation: public MyCalculatorInterface {
...
};
}
// Only the ctor needs to know about MyCalculatorImplementation
// in order to make a new one.
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
markshiz and quamrana provided the inspiration for the solution below.
class Implementation, is intended to be declared in a global header file and serves as a void* for any pimpl application in your code base. It is not in an anonymous/unnamed namespace, but since it only has a destructor the namespace pollution remains acceptably limited.
class MyCalculatorImplementation derives from class Implementation. Because pimpl is declared as std::unique_ptr<Implementation> there is no need to mention MyCalculatorImplementation in any header file. So now MyCalculatorImplementation can be implemented in an anonymous/unnamed namespace.
The gain is that all member definitions in MyCalculatorImplementation are in the anonymous/unnamed namespace. The price you have to pay, is that you must convert Implementation to MyCalculatorImplementation. For that purpose a conversion function toImpl() is provided.
I was doubting whether to use a dynamic_cast or a static_cast for the conversion. I guess the dynamic_cast is the typical prescribed solution; but static_cast will work here as well and is possibly a little more performant.
#include <memory>
class Implementation
{
public:
virtual ~Implementation() = 0;
};
inline Implementation::~Implementation() = default;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
std::unique_ptr<Implementation> pimpl;
};
namespace // Anonymous
{
class MyCalculatorImplementation
: public Implementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
MyCalculatorImplementation& toImpl(Implementation& impl)
{
return dynamic_cast<MyCalculatorImplementation&>(impl);
}
}
// no error C2872 anymore
MyCalculator::MyCalculator() : pimpl(std::make_unique<MyCalculatorImplementation>() )
{
}
int MyCalculator::CalculateStuff(int x)
{
return toImpl(*pimpl).Calculate(x);
}
I'm having an issue with a C++ library I'm trying to write. It's the usual setup, one cpp file, one header file. I want the header file to only expose the parts that are meant to be used (I have an abstract base class for instance, I don't want in the header file). So far, I'm just working with a single file (I assume this should make no difference, as includes are done by the preprocessor, which doesn't care about anything).
You'll note that the "header file" is spread over two spots, before and after the header implementation file.
#include <stdio.h>
// lib.h
namespace foo {
template <class T> class A;
}
// lib.cpp
namespace foo {
template <class T> class A {
private:
T i;
public:
A(T i) {
this->i = i;
}
T returnT() {
return i;
}
};
};
// lib.h
namespace foo {
template <class T> T A<T>::returnT();
}
// foo.cpp
void main() {
foo::A<int> a = foo::A<int>(42);
printf("a = %d",a.returnT());
}
So, naturally, I'd like my header file to contain just
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
But my compiler does not like this (it complains that returnT is not a member of foo::A<T>. The reason I don't want to put the class declaration itself in the header is that then it would (as I understand it), contain all the private and similar stuff, which I'd like to hide.
Maybe it's just me, but the following header file seems "bad", at least as an "interface specification." It exposes some of the internals of A, which a user of the lib would not need to know about.
// lib.h
namespace foo {
template <class T> class A {
private:
int i;
public:
A(T);
T returnT();
};
}
// lib.cpp
namespace foo {
template <class T> A<T>::A(T i) {
this->i = i;
}
template <class T> T A<T>::returnT() {
return i;
}
};
Is this the accepted way of doing it? I'd like a more abstract header file, if at all possible.
You cannot separate the definition of a template from its declaration. They both have to go into the header file together.
For "why?" I recommend reading "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?".
I may have misread your question. To address what may also be your question, this is not valid:
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
It is not valid for the same reason that this is not valid:
namespace foo {
class A;
int A::returnT();
}
Member functions must be declared inside the definition of the class.
There are two problems with .cpp files you are dealing here:
I.
If you want to put an instance of that class on the stack (like you do in your main()) the compiler needs to know the size of the class (to allocate enough memory). For that it needs to know the members and by that the complete declaration.
The only way to hide the class' layout away is to built up an interface and a factory method/function and put the instance on the heap in the factory.
As an example (without the template; see below to know why):
namespace foo {
class IA {
public:
virtual ~IA();
virtual int returnT() = 0;
static IA *Create();
};
}
In your .cpp you then do:
namespace foo {
class A : public IA {
private:
int i;
public:
A() :
i(0) {
}
virtual ~A() {
}
virtual int returnT() {
return i;
}
};
IA::~IA() {
}
IA *IA::Create() {
return new A();
}
}
BTW: Using smart pointers would be suggested...
II.
Since you are using a template the method definitions must be either visible via header file or explicitly instantiated for a specific set of types.
So you can split up your code into a lib.h and a lib_impl.h:
lib.h:
namespace foo {
template <typename T> class IA {
public:
virtual ~IA() {
}
virtual T returnT() = 0;
static IA *Create();
};
}
lib_impl.h:
namespace foo {
template <typename T> class A : public IA<T> {
private:
T i;
public:
A() :
i(T()) {
}
virtual ~A() {
}
virtual T returnT() {
return i;
}
};
template <typename T> IA<T> *IA<T>::Create() {
return new A<T>();
}
}
so you include the lib_impl.h where ever you need the impleemntations.
To use the explicit instantiations add a lib.cpp and just let that file allow to include lib_impl.h:
lib.cpp:
#include <lib_impl.h>
namespace foo {
template class IA<int>;
template class A<int>;
template class IA<float>;
template class A<float>;
template class IA<char>;
template class A<char>;
// ...
}