I'm exploring template shenanigans in C++ (C++11), and one thing I'd like to have is a pure virtual type in an abstract class. This would be like Scala's abstract types. In C++ I'd want to do something like the following:
struct Base {
// Says any concrete subclass must define Type, but doesn't
// require that it be anything in particular.
virtual typedef MyType;
};
struct Derived : Base {
// Won't compile unless this typedef exists.
typedef int MyType;
};
Any idea how to do this?
I am not sure there is a real need for this in C++.
Trying to put myself in the position of a designer who is looking for such a solution, I would say this kind of constraint would be needed to enforce some types to adhere to some syntactic convention.
Most likely, this is needed because a generic algorithm requires that syntactic convention: it cannot work with types that do not define such a type association.
For instance, the algorithm below requires the type of its argument to have an associated bar_type:
template<typename T>
bool foo(T t)
{
typedef typename T::bar_type FT;
FT ft;
...
}
But if this is the case, there is no need for enforcing a typedef to effectively constraint the input of foo<>(): simply omitting a type definition for bar_type won't make it possible to use that type with foo<>().
Of course, you would discover this only as soon as you actually try to do so, and not before. And being able to define a concept such as HasBarType, and then to enforce some types to realize that concept would be nice; on the other hand, concepts are not yet part of C++ and, as much as they are desirable, it is possible to live without them.
edit
This doesn't work, but I think the curiously recurring template pattern might be the way to go.
/edit
template<typename Dependent>
class Base : public Dependent {
typedef typename Dependent::MyType MyType;
};
Then use the curiously recurring template pattern:
struct Derived : Base<Derived> {
// Won't compile unless this typedef exists.
typedef int MyType;
};
Related
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);
}
Say I have a template class:
template <typename T> class StringDeque:
public std::deque<T>
{
public:
...
private:
typedef std::deque<T> BaseClass;
};
Say I want to create concrete class ArrayString where T=std::string.
What is the proper way to achieve that:
define
#define ArrayString StringDeque<string>
typedef
typedef StringDeque < string > ArrayString;
inheritance
class ArrayString :
public StringDeque < string > {};
I'm not sure whether all of the suggestions are valid. Anyway I'm trying to figure out which practice most fits.
You want to give a name to a particular type (which happens to be an instantiation of a template). The C++ way to give names (aliases) to types is with a typedef:
typedef StringDeque<string> ArrayString;
Or, since C++11, with an alias declaration:
using ArrayString = StringDeque<string>;
Side note: when thinking about this stuff, it generally helps to think in terms of the correct template terminology. You don't have a "template class" (a class with special properties), you have a "class template" (a template for creating classes). The template is not a type; its instantiations are.
Proper ways:
typedef std::deque<std::string> StringDeque;
using StringDeque = std::deque<string>;
That said, here are some more notes on your question:
You wrote:
template <typename T> class StringDeque: public std::deque<T> // ...
std container classes are not meant as base classes. This means they should not be inherited from (and inheriting from them is UB).
When you want to use std container functionality in another class, the answer should always be encapsulation. That means, the correct way to build on the functionality of std::queue in your classes is:
template<typename T> class StringDequeue {
std::deque<T> storage;
public:
// add interface here that uses storage
};
You also proposed this:
#define ArrayString StringDeque<string>
Please never use define to declare a type. It works, but it has it's own pitfalls and is considered bad practice in C++.
Create type aliases with typedef or (since C++11) using:
typedef StringDeque<std::string> ArrayString;
using ArrayString = StringDeque<std::string>;
The preprocessor is a sledgehammer: occasionally useful but, with no knowledge of language-level constructs, prone to break code in surprising ways. In this case, I think the only problem is that the name won't be constrained to any scope; but that's reason enough to avoid it.
Inheritance creates a new type; while it's usually usable where the base type is, it's not completely interchangable, and doesn't inherit any constructors from the base type. So that's also not what you want for a simple type alias.
Suppose we have a templated class,
template<typename Type>
class Container {};
Of course, we can't do this:
struct Foo
{
Container _container;
}
But what if we wanted to do something like it? Is the only way to do this, to define a base class,
class ContainerBase {};
template<typename Type>
class Container : public ContainerBase {};
and store a pointer, like below?
struct Foo
{
ContainerBase* _container;
}
It's simple enough, but it feels weird to have to add a base class solely for that reason, when it seems the compiler should have enough information to imply a set of related specializations. Of course, regardless _container needs to be a pointer, else Foo couldn't resolve to a static size, but
struct Foo
{
Container* _container;
}
doesn't work either.
it seems the compiler should have enough information to imply a set of related specializations.
Nope. Template specializations are totally unrelated except in name, and the name of a type has essentially no bearing on runtime operation. Specializations of a given template usually share a (mostly) common interface, but they could just as well be completely different.
Adding a base class is essential if you want to relate between the specializations. And if they share so much in common, factoring that functionality into the base is a pretty great idea.
I have a tricky question about C++(11) template classes and their instantiation with types determined at runtime:
Following scenario:
The user defines the type of a template class using a config file (ROS parameters). This determines only the type of the template class, not the further logic:
Class definition:
template<typename T>
class MyClass {
//[...]
}
Exemplary code:
/* [Read parameter and write result to bool use_int] */
std::unique_ptr<MyClass> myclassptr {nullptr};
if(use_int) {
myclassptr.reset(MyClass<int>);
} else {
myclassptr.reset(MyClass<double>);
}
myclassptr->foobar();
/* [more code making use of myclassptr] */
So this code is (of course) not compiling, because the unique_ptr template must be specified also with the template type. However, then the problem arises that the template type must be the same for all objects assigned using reset.
One ugly solution would be to copy the code myclassptr->foobar(); and the following into each branch of if/else, which I really don't like.
I would like to see a solution similar to this:
/* [Read parameter and write result to bool use_int] */
MyClass<use_int ? int : double> myclass;
myclass.foobar();
What I have read so far is that something like this is also not possible.
Does anybody have a nice solution for this?
The simplest way to do this is:
class IClass{
virtual ~IClass {}
virtual void foobar()=0;
};
template<typename T>
class MyClass:public IClass {
public:
void foobar() override {
// code here
}
};
std::unique_ptr<IClass> myclassptr {};
if(use_int) {
myclassptr.reset(new MyClass<int>());
} else {
myclassptr.reset(new MyClass<double>());
}
myclassptr->foobar();
boost::variant would be another solution, but is usually used for unrelated types. Type erasure could be done, but again that is usually done when you have unrelated types you want to impose a uniform interface on.
In other languages generics look sort of like templates, but are actually an abstract interface with auto-generated typecasting and some typechecking added. C++ templates are function or class compile time factories. Two outputs of such factories are unrelated at runtime by default, and you can add such relations if you want.
Depending on what you want, you can make MyClass a variant type that holds either an int or a double, or you could use type erasure to hide the implementation behind an interface. The Boost.Variant library can help to implement the former.
Catch-all traits classes like std::iterator_traits are useful by separating the properties of a type from its definition, so for example the properties may be made available before the definition is complete.
Defining traits in addition to each client class itself is inconvenient, because the traits typically also have a place as members. This is why the generic implementation of std::iterator_traits is defined in terms of its template argument's members.
template< typename it >
struct iterator_traits {
typedef typename it::category category;
typedef typename it::value_type value_type;
// etc
};
Isn't it easier, and less work for the compiler, to use inheritance instead?
template< typename t >
struct t_traits : public t {
t_traits() = delete; // Prevent runtime instances.
};
This fails to document the interface in the primary template, but there are other opportunities for that anyway.
It seems pointless to write lots of repetitive code to define a meta-container class, in an idiom which doesn't even guarantee prevent such abuse as creation at runtime.
Or maybe that's entirely backwards. In addition to std::iterator_traits we also have std::iterator, a pseudo-abstract base class with mostly the same members. Such redundancy is a code smell. Wouldn't it be better if custom iterators looked like this?
template<>
struct iterator_traits< struct my_iterator > {
typedef random_access_iterator_tag category;
typedef foo value_type;
...
};
struct my_iterator : iterator_traits< struct my_iterator > {
...
};
(For the sake of argument, let's ignore the fact that an actual std::iterator_traits specialization must be declared in namespace std. I'm trying to make a familiar illustration of something that might happen in user code.)
This is cleaner in that the idiom need not be violated to handle whatever exceptional case necessitated the fancy footwork in the first place. Instead of the primary traits template producing an internal error that the missing client class is unsuitable for something, there need not be any primary traits template at all.
It's conceptually better to separate qualities of a class from implementation of its services, regardless of whether that separation is necessary. BUT, this style does require breaking every client class into two pieces, including an explicit specialization, which is sort of ugly.
Is anyone familiar with this design space? I'm leaning toward the second idiom, although it looks unusual in practice. But there are probably ins and outs known to those who have trod here before.
The problem with user-defined traits as a specialization of a library type is that a library type belongs to the library. Defining an explicit specialization requires opening the library namespace, which is ugly.
Alternatives 1 and 2 can be combined into a best of both worlds pattern that
always allows optimal separation of concerns (by splitting a class into traits and implementation)
doesn't require splitting a class
never requires opening the library namespace
An extra bit of glue is needed in the form of an ADL based metafunction mapping any class to its traits.
template< typename t >
t traits_type_entry( t const & ); // Declared, never defined.
template< typename t >
using traits_type = decltype( traits_type_entry( std::declval< t >() ) );
By default, T serves as its own traits type as traits_type< T >::type is T. To change this for a given type t to a traits class t_traits, declare (but do not define) a function t_traits traits_type_entry( t const & ). This t_traits class may or may not be a base class of t; the traits_type facility doesn't care. Because the function will be found by argument-depenedent lookup, it may be declared as a friend function with no declaration at namespace scope.
Usage nested inside a class (just to make a difficult test-case) looks like this. For usual usage in a namespace just drop the friend keyword.
class outer_scope {
struct special;
struct special_traits {
typedef int value_type;
constexpr static int limit = 5;
};
friend special_traits traits_type_entry( special const & );
struct unspecial {
typedef double baz_type;
int table[ util::traits_type< special >::limit ];
};
struct special : special_traits {
void f() {
std::pair< typename util::traits_type< unspecial >::baz_type,
value_type >();
}
};
};
http://ideone.com/QztQ6i
Note, the t const & parameter to traits_type_entry can be simply t as long as the class is copyable and destructible.
Also, you could prevent declaring an object of (non-customized) trait type by having the primary template return a type derived from t with its constructor deleted, instead of t itself.