I'm probably over reaching here to solve what should be a simple problem. I started this question here:
Getting type of base class at compile time
Basically I'm trying to make the class manage it's own pointer types. I'm wrapping a C library where some structures have reference counting embedded in them, and others do not. Those that don't, I'd like to use shared_ptr. Those that do, I'd like to use intrusive_ptr. I'd like to avoid relying on programmer intellect to ensure the use of the proper wrapper. Eventually, I'd like to add more capability that relies on this behavior, but I'm not there yet.
#Yakk came up with an interesting solution using template type aliases, and I've tried to implement it. Unfortunately I've got myself in a spot where I can't seem to resolve circular references to the compiler's satisfaction. I get an "incomplete type 'Test2' named in nested name specifier" error pointing to the "using pointer=" line. I also get a bizarre "definition differs from declaration in return type" for my definition of Test::f(), but I suspect that might resolve itself once I get the first error resolved.
Most of the references I find on this error type involve sequencing of header files, but even with everything in one file I can't figure out how to order things to make this problem go away.
Any ideas?
#include <iostream>
#include <memory>
template<typename T>
class Pointered: public std::enable_shared_from_this<T>
{
public:
using pointer=std::shared_ptr<T>; //<-- incomplete type named error
using weakPointer = std::weak_ptr<T>;
};
template<typename T>
using Ptr = typename T:: pointer;
template<typename T>
using WkPtr = typename T:: weakPointer;
class Test2;
class Test:public Pointered<Test>
{
public:
Ptr<Test2> f();
};
class Test2:public Pointered<Test2>
{
public:
Ptr<Test> p;
Test2(Ptr<Test> ptr):p(ptr){}
};
int main(int argc, const char * argv[])
{
Ptr<Test> p=std::make_shared<Test>();
Ptr<Test> p3=p;
p->f();
std::cout << "Refcount: " << p.use_count() << std::endl;
}
//definition differs from declaration in return type error here
Ptr<Test2> Test::f()
{
return Ptr<Test2>(new Test2((Ptr<Test>)shared_from_this()));
}
You cannot forward declare nested types, for that you need the definition of the enclosing type, but in your case you have a cyclic dependency that inhibits this.
The first thing to consider is whether the cyclic dependency is really a good idea. In most cases cyclic dependencies are considered a code smell (an indication of problems with the design). If you can remove the cyclic dependency, then everything will become easier.
A different alternative is moving the dependency on the nested type to a type-trait, that can be defined externally and before the definition of the types:
template <typename T>
struct pointer_traits;
template <>
struct pointer_traits<Test1> {
typedef std::shared_ptr<Test1> ptr;
typedef std::shared_ptr<Test1> wptr;
};
By moving the dependency outside of the real type, you no longer have the cyclic dependency (at the syntax level, you should still revisit the design). You can then add syntactic sugar as needed:
template <typename T>
using ptr = typename pointer_traits<T>::ptr;
class Test1 {
ptr<Test2> p2;
};
If you really want the types to also be nested, you can use inheritance to bring those into scope, or in a simpler way just add the appropriate typedef:
class Test1 {
typedef ptr<Test1> ptr_t;
// ...
Note, this is a rough approximation, if you opt for this approach you can work a bit on the details of the trait and the types to make it sweeter by adding more syntactic sugar, for example, you can provide two traits for shared_ptr_traits and intrusive_ptr_traits and provide a single line trait to determine from which of those you want to pull the typedefs, reducing the definition of the trait (per type) to a single line.
Related
Is it possible (and is it a good idea) to conditionally define methods for some container class (template<typename ThingType> class Container) depending on the type of its elements? I first thought it was possible after reading about std::enable_if, but now I am not certain I understand.
Below is my attempt (click here to run on ideone). In the case that std::is_base_of<ThingBase, ThingType>::value is false, a return type for p will not be defined. I figured the compiler would just instantiate the object of a class without that method. But it turns out it doesn't compile.
Is there another tool for the job? Or should I write two Container-like classes that have different behavior depending on what ThingType is? Or maybe this is a job for a specialization.
#include <iostream>
#include <type_traits>
#include <vector>
class ThingBase {
public:
virtual void printHi() = 0;
};
class Thing : public ThingBase
{
void printHi(){
std::cout << "hi\n";
}
};
template<typename ThingType>
class Container{
private:
std::vector<ThingType> m_things;
public:
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
{
m_things[0].printHi();
};
};
int main() {
//Container<Thing> stuff; // works!
Container<int> stuff; // doesn't work :(
return 0;
}
Edits:
The error message from the compiler is
prog.cpp: In instantiation of ‘class Container<int>’:
prog.cpp:36:17: required from here
prog.cpp:26:78: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
#StoryTeller - Unslander Monica I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
This simplifies the exercise quite a bit. The solution is... to do nothing special.
void p() {
m_things[0].printHi();
}
When a class template is implicitly instantiated, only the declarations of member function are instantiated along with it. Definitions are not instantiated until an attempt is made to use the member.
So you do not need to do anything special. The error will happen if it's used when it cannot be used.
If still you wish to ensure derivability, and produce a descriptive error in that case, you can add a static_assert to the member function body. Simply use the is_base_of test for a condition, and add a nice string to accompany it.
This is a common approach when writing generic utilities. SFINAE's primary purpose on the other hand is to control overload resolution. But you aren't doing it here.
I'm trying to deal with circular dependency in following scenario:
I've got a std::variant, say:
//types.h
using Types = std::variant<int, double, std::string, SomeClass>;
SomeClass is a pretty simple thing holding few pointers, with some template logic:
#someclass.h
class SomeClass {
// few simple members (pointers and an integer)
void use(Types arg); // note usage of Types here
template<typename T, typename Ts...> // implicitly assuming T == Ts... == Types
void use(T arg, Ts... tail) {
use(arg);
use(tail...);
}
SomeClass(const SomeClass&) = default; // works fine
};
Usually I would forward-declare SomeClass before "using Types...", but it can't be done when it comes to std::variant. I also didn't really found a way to forward-declare the "using" directive.
One way I found was forward-declaring SomeClass and using a pointer to it in Types, but I don't like this idea (SomeClass is a really light object with short lifespan, I'd want to keep it out of heap).
Is there any other way (beside pointers) in C++ to solve this one? I'm running out of ideas.
Thanks :)
EDIT:
The issue actually appears only if I'm trying to use Types before really defining SomeClass, see https://godbolt.org/z/4jzhEd
In the live example you provided, all you need to solve the issue is define SomeStruct after SomeClass.
This way your Types variant will no longer have any incomplete types when SomeStruct is defined. In other words, here is the order:
class SomeClass;
using Types = std::variant<..., SomeClass>;
class SomeClass {
// ... // Types used here, but doesn't need to have all complete types
};
struct SomeStruct {
Types value;
// ...
};
See here for a live example.
How to self-document a type-alias that is used in another certain library?
In the below example, class User defines an alias User::type that is supposed to be referred only in class Library via T::type.
Here is the diagram :-
Library.h
Library<T> expected only T that defines a certain alias (e.g. T::type in this example).
#include <iostream>
class Base{}; //dummy for the sake of example
template<class T>class Library{
Base* t=nullptr;
public: typename T::type getValue(){return static_cast<typename T::type>(t);}
//some complex function, e.g. T::aType::doSomething()
};
In real cases, Library<T> expected many alias e.g. T::aType, T::bType, T::callbackType, etc.
User.h
To use the above library, ::type has to be defined e.g. as below :-
class Derived : public Base{}; //dummy for the sake of example
class User{
public: using type=Derived*;//<-- poorly documented
//... other alias e.g. aType=int*, bType=SomeClass*
//... other complex functions
};
Here is the usage (full demo):-
int main(){
Library<User> lib;
lib.getValue();
std::cout<<"OK"<<std::endl;
}
Problem
Notice that User::type really lacks self-documentation.
In real life, most coders - including ones who designed it - forget what User::type is for.
User::type is not referred internally in User.h, so it is an easy target to be randomly deleted by some coders.
I feel that our beloved codes are rotten from inside, and I think about ways to save it.
Question
How to self document the type alias to indicate how/where it is called?
My poor solutions
1. comment
class User{
/** It is used for Library.h */
public: using type=Derived*;
It gets dirty pretty fast, and I still prefer using C++-semantic rather than random comment.
2. make the type name more descriptive
class User{
/** It is used for Library.h */
public: using LIBRARY_type=Derived*;
It is quite messy.
Note: This question is similar to How to self-document a callback function that is called by template library class?, but this one is about type-def while that one is about callback.
It seems that your only actual problem here is that "it is an easy target to be randomly deleted by some coders".
The solution to this is not to obsess over self-documentation and names, but to institute peer review and regression tests. Why are coders on your team "randomly deleting" things and getting away with it? That needs to stop.
You can probably save the administrative headache of having to rollback such a change, with a simple code comment:
/**
* Provided for use by Library.
*/
using type=Derived*;
That's it. That's all you need. It's not "dirty" in the slightest — it tells other coders why the type declaration exists, and will stand out like a sore thumb in diffs if anyone removes it. Then you can ask them, "how did you conclude that Library no longer requires this declaration, and why is removing it worth the breakage of our API?"
In short, this is only a human problem. There are plenty of examples in the standard library of member types called type, so from a technical standpoint you're already doing what you should. Don't try to shoe-horn in names that reflect your type's expected usage; make the name describe what it is. The C++ committee made the same mistake with std::move!
You may create a type traits for that:
template <typename T> struct library_trait; // No definition
// Need to define library_trait<T>::type for ...
// library_trait<T>::atype for ...
In class Library, use library_trait<T>::type instead of typename T::Type
In a place before the usage of Library<User> (as in main in your example):
Specialize library_trait for User.
template <> struct library_trait<User>
{
using type = Derived*;
// ...
};
A trait class is the usual solution to this problem. It is awkward because you have to specialize it within its own namespace.
An alternative is to create a trait function.
namespace utility {
template<class T>struct tag_t{using type=T; constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
template<class Tag> using type_t=typename Tag::type;
}
namespace MyLibrary {
template<class T>
void library_trait_name_f(tag_t<T>,...);
template<class T>using library_trait_name=type_t<decltype(library_trait_name_f(tag<T>))>;
}
now suppoae you have:
namespace Elsewhere {
struct Foo;
}
you can write anywhere:
namespace Elsewhere { // or MyLibrary, or even utility
tag_t<int> library_trait_name_f(tag_t<Foo>);
}
and if visible it will be picked up by MyLibrary::library_trait_name<T>. In particular, MyLibrary::library_trait_name<Elsewhere::Foo> is int.
The advantage of this is that it permits you to write thr binding between the library and the type in the library, next to the type, or in a 3rd location. The big disadvantages is the lack of scoping and the unconventionality of it.
MSVC also doesn't behave well with decltype based SFINAE, so using the above for SFINAE in MSVC you need be careful.
I went through some searches but couldn't quite find this one. Consider this situation:
template <class T> class TemplClass;
void a_function(TemplClass<const X>&);
TemplClass<X> inst;
a_function( inst ); // fails
"invalid initialization of reference of type ‘TemplClass&’ from expression of type ‘TemplClass’"
The situation is 100% safe as far as I can tell. Still, C++ does not allow this. So I wonder what cast to use instead of the trivial C-cast.
a_function( static_cast<TemplClass<const X>&>(inst) ); // fails, similar error message
a_function( reinterpret_cast<TemplClass<const X>&>(inst) ); // works
dynamic_cast is out of the question, const_cast fails too (and rightly so).
The reinterpret_cast feels fishy (is it though?). But is there a solution with some kind of trick that I missed? Anyone know why the standard does not simply detect that this is something good? Or is there something 'bad' about this cast?
TemplClass<const T> and TemplClass<T> are unrelated types.
For example you may have (partial) specialization to make them really different:
template<typename T>
class TemplClass
{
void generic();
std::string s;
};
template<typename T>
class TemplClass<const T>
{
void foo();
std::vector<int> v;
};
Casting one into the other doesn't make sense.
In the same way
class A
{
char* p;
};
class B
{
char* p;
};
Those 2 classes are unrelated (even if it seems identical).
But is there a solution with some kind of trick that I missed?
The ideal solution is to not write such restricted template interfaces. For example, consider the standard library algorithms that take iterators to represent ranges rather than specific template types with specific object types.
If you're unable to fix the interface as it's say in a third party library, then you're going to be stuck copying your Templ<X> to a Templ<const X> before making the call.
Anyone know why the standard does not simply detect that this is
something good?
Because it's not good. The very simplest case is where there are template specializations where it would change some meaning/functionality. The compiler can't simply change the instantiation of the template.
Or is there something 'bad' about this cast?
By the language, the cast is illegal because the const and non-const template instantiations are unrelated types. Depending on the actual case, there are probably legal alternatives.
Is there a way to check if class has a typedef which works even for private typedef?
Following code works in VS2013, but fails on ideone's gcc
template<typename T>
struct to_void
{
typedef void type;
};
class Foo
{
typedef int TD;
};
template <typename T, typename dummy = void>
struct has_TD : std::false_type {};
template <typename T>
struct has_TD<T, typename to_void<typename T::TD>::type > : std::true_type{};
int main()
{
std::cout << std::boolalpha << has_TD<Foo>::value << std::endl;
}
edit - why I want this
I have custom serialization system, which can serialize arbitrary type. It has several overloads when it must behave differently (for example string). For the rest of the types, it simply writes the value in the memory. If I have composed type, I can sometimes just write into memory as well (save & load happens on the same architecture, compiled with the same compiler, so paddings will be the same, etc.). This method is valid for example for POD types (std::is_pod trait), but all POD types is only a subset of all types, supporting this serialization.
So I basically have templated function write<T> which just write sizeof(T) bytes (raw-serialization)... But I don't want this to be called by mistake, I want user, to explicitly say in their class: "this class/struct can be raw-serialized"). The way I do it is a macro ALLOW_RAW_SERIALIZE which defines some typedef which can be checked via trait. If class MyClass doesn't contains typedef, calling write(myClassInstance) will produce compiler error.
The things which which basically decide if class can be raw-serialized are its members (without reflection, members cannot be enumerated and checked automatically, so user have to provide such information). typical class looks like this:
class
public
ctor-dtor
methods
private
methods
members
and I want users to allow write ALLOW_RAW_SERIALIZE as close to the members as possible, so when they change some members there is a lesser chance to forgot about updating ALLOW_RAW_SERIALIZE (remove it. when it's no longer valid)
So that is why I want to check a private typedef
Since it's substitute for reflection and takes whole type and write it, I don't fell about it like breaking encapsulation or so...
UPDATE:
Okay, did a little research.
FYI, the [probable] reason that ideone didn't compile is that what you're doing needs -std=c++11 [or higher]. I got similar errors before adding that. But, I had to use clang++ as g++ still had problems compiling if TD was private.
But, I'm not sure this works as the only combo that printed true was if TD was public. All others of public/private and changing TD to TF produced false. Maybe VS2013 works [why?], but two other compilers have issues, either in compilation or runtime results--YMMV.
The basis for what you're doing is std::integral_constant [since c++11]. There appears to be no standard derivation from this for what you're doing. That is, from http://www.cplusplus.com/reference/type_traits/integral_constant/ the list of type traits [on the left] has nothing that matches your use case [AFAICT].
Nor does Boost.TypeTraits have anything that matches up [again, AFAICT].
From Andrei Alexandrescu's book: "Modern C++ Design: Generic Programming and Design Patterns Applied", section 2.10 Type Traits:
Usually, you will write your own trait templates and classes as your generic code needs them. Certain traits, however, are applicable to any type. They can help generic programmers to tailor template code better to the capabilities of a type.
So, it's "okay" to roll your own, if you wish.
But, even the TypeTraits he talks about [from Loki], again, doesn't have anything that matches what you're doing.
Since neither std nor Boost has anything, then the question becomes "what is standard?" [from your perspective]. There may be "fludger" c++ traits library somewhere that has an implementation, but would that be considered "standard"? YMMV
However, a question or two:
Why would one do this? What is the use for it? What about a protected typedef in a base class?
And, this seems to require knowledge of the private part of a class, and wouldn't that be a violation of either "data hiding" or encapsulation [without a friend declaration of some sort]?
So, if that last question is true, the probable [IMO] answer is that there is no standard way to do this, because it's not something one should be doing in a standard library.
Side note: This is the part that got downvoted (before I [truly] understood the question). I believe I've acquitted myself above. So, disregard the answer below.
When you use class the default visibility is private. With struct, it's public.
So, either do:
struct Foo
Or:
class Foo
{
public:
typedef int TD;
};
This is, of course, assuming that you want TD to be public
If all you need is compile time checking then following code should do:
#include <iostream>
class Foo
{
typedef int TD;
template<typename T> friend class has_TD;
};
template <typename T>
struct has_TD
{
typedef typename T::TD type;
};
template <typename T, typename has_TD<T>::type = 0>
void write(const T& /*data*/)
{
std::cout << "serialize" << std::endl;
}
int main()
{
Foo foo;
write(foo);
}