C++ Function templates with templatized arguments - c++

I am trying to write a function which can take any of the standard containers(list, stack, vector etc) as it's arguments. I also wish to know the type that is within the container. Here is what I have tried.
#include<iostream>
#include<list>
#include<vector>
template<class data_type, template<class> class container_type>
void type(container_type<data_type>& _container){
std::cout<<typeid(container_type).name()<<std::endl;
}
int main(){
std::list<int> list_t;
std::vector<int> vector_t;
type(list_t);
type(vector_t);
}
The type of container_type once inside this function is always _Container_base_aux_alloc_empty which(I think) is a base class of the standard containers.
What is going on here?
How would I make this function return the correct type?

The typeid of container_type is no use, because that's just a template class, and a template class isn't a real type at all, it only becomes one after instantiation. So what you really want is the type of data_type for the value type, and the type of container_type<data_type> for the type of the instantiated container. Even better, of course, is to take container_type<data_type>::value_type as the value type.
Note that most containers take more than one template parameter, so you'd be better off writing this with variadic templates:
template <template <typename...> class Container, typename ...Args>
void print_type(const Container<Args...> &)
{
typedef typename Container<Args...>::value_type value_type;
print(typeid(Container<Args...>).name());
print(typeid(value_type).name());
}

Your code won't work, because as soon as someone swaps out the allocator or something like that, then you're done for. You should take any T and use ::value_type, if in C++03, or type deduction in C++0x.
Also, .name() isn't defined to return anything useful, at all. In any situation. An implementation could return "har har sucker! good luck using this language feature" for every type and be conforming.

I would not trust the output of typeid() that much. type_info::Name is not guaranteed to return some unique identfier. So it might very well be the type inside the function is what you expect.
The best way to get some kind of name for the type is to use a macro, something like this:
template<class data_type, template<class> class container_type>
void type_helper(container_type<data_type>& _container, const char* charStr){
std::cout<< charStr << std::endl
}
#define type(container) type_helper(container, #container)

You already have the type of the container. It's data_type. Just use it like this. If in doubt you can also use typename container_type::value_type which is a typedef for the template argument of the container.
So much for using types. Returning a type is something entirely different in C++ and is generally considered a part of template meta-programming.
This, rather pointless snippet, extracts the value_type from some type T.
template<typename T>
struct inner_type {
typedef T::value_type value_type;
};
But you might as well use the value_type directly and avoid this piece of obfuscation.

Related

C++ template metaprogramming: how to deduce type in expression pattern

I am want a static check of the parameter type of lambdas. I've written this code below and it seems to produce the correct result.
struct B { };
auto lamBc = [](B const& b) { std::cout << "lambda B const" << std::endl; };
template<typename ClosureType, typename R, typename Arg>
constexpr auto ArgType(R (ClosureType::*)(Arg) const)->Arg;
template <typename T>
using ArgType_t = decltype(ArgType(&T::operator()));
// ArgType_t<lamBc> is "reference to B const"
However, I noticed that, for example, the standard library uses class template specialization to extract the referred-to type from a reference type in std::remove_reference. So I tried that approach and it also seems to produce the correct result.
template<typename L>
struct ArgType2;
template<typename ClosureType, typename R, typename Arg>
struct ArgType2<R (ClosureType::*)(Arg) const>
{
typedef Arg type;
};
template <typename T>
using ArgType2_t = typename ArgType2<decltype(&T::operator())>::type;
// ArgType2_t<lamBc> is also "reference to B const"
My questions are: Which is the standard way to extract types from a pattern expression? What are the trade-offs in either approach?
Both your approaches are valid, interchangeable and lead to the same result (deduce the type of the parameter lambda accepts).
For type traits it is required by the standard (see 23.15.1 Requirements) that:
A UnaryTypeTrait describes a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the property being described. ...
A BinaryTypeTrait describes a relationship between two types. It shall be a class template that takes two template type arguments
and, optionally, additional arguments that help define the
relationship being described. ...
A TransformationTrait modifies a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the modification. ...
I suppose that this requirement appeared mostly for historical reasons as decltype functionality was introduced after type traits had been proposed (and these type traits were based on type traits from boost which had been created even earlier, see, for example, this).
Also, note, that class templates are more flexible for general purpose type traits than the logic based on functions declarations and decltype.
The main point is that with C++11 and later in your particular case you are free to use the way which is the most convenient and reflects the programming logic better.
They are both "standard", the decltype() way is simply available in modern C++ variants, the PTS method was the only way to do this sort of things under the original C++ standard.

meaning of c++ struct syntax with only typedef

When I examine some code snip from some libraries, I saw some code like this:
template<typename _Function, typename _ReturnType>
struct _TaskOfType_ContinuationTypeTraits
{
typedef task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType> _TaskOfType;
};
Can someone provide some explanation of the code? What is it trying to do and what is the advantage to use a struct with only typedef statement within the body?
In C++ parlance, the _TaskOfType_ContinuationTypeTraits is a metafunction. It does type computations at compile-time.
A metafunction is in a way similar to a run-time function. The key difference is that the input arguments to a metafunction are type(s), and returns are also type(s).
Eg. The following metafunction takes a type, and returns a pointer of the type you supply to it.
template <typename T>
struct add_pointer
{
typedef T* type;
}
Now, if you did add_pointer<int>::type, it returns int*. You see, you gave it a type (int in this case) and the compiler computed a new type (int* in this case) and gave it back to you when you invoked the ::type of the metafunction. When you do ::type on a metafunction, that is when the template is instantiated. This is the run-time equivalent of calling a function. Also note that all of this happened at compile-time!
Now, going back to your _TaskOfType_ContinuationTypeTraits. This is just like my add_pointer. In add_pointer, I just had one template argument, you have two. I just added a pointer to the type that was supplied, you have something much more complicated. But, at it's essence, it is only a type computation. My add_pointer returns when I call ::type on it, yours does when you call ::_TaskOfType.
This kind of syntax is used to create "templated typedefs". In C++11 and above, type aliases / alias templates should be used instead.
The purpose of the code snippet you posted is to create a type alias that depends on _Function and _ReturnType.
It can be accessed like this:
typename _TaskOfType_ContinuationTypeTraits<F, R>::_TaskOfType
If you have access to C++11, this is a cleaner, better and more straightforward solution:
template<typename _Function, typename _ReturnType>
using _TaskOfType =
task<typename _TaskTypeTraits<
typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType>
Which can be used like this:
_TaskOfType<F, R>
More info: "Difference between typedef and C++11 type alias"

Why does C++11 not have template typedef?

Why does C++11 not have "template typedefs", like
template<typename T> typedef std::vector<T, myalloc<T>> vec;
Instead they only allow the new syntax:
template<typename T> using vec = std::vector<T, myalloc<T>>;
n1406 was the proposal by Herb Sutter for "typedef templates" which mimics the syntax in your question. n1499 which proposes "template aliases" supersedes it, which contains the using syntax that's currently present in C++11.
One of the main drawbacks of the "typedef templates" is addressed in both papers. From n1406:
In existing practice, including in the standard library, type names
nested inside helper class templates are used to work around this
problem in many cases. The following is one example of this usual
workaround; the main drawback is the need to write ::Type when using
the typedef’d name.
template< typename T >
struct SharedPtr
{
typedef Loki::SmartPtr
<
T, // note, T still varies
RefCounted, // but everything else is fixed
NoChecking,
false,
PointsToOneObject,
SingleThreaded,
SimplePointer<T> // note, T can be used as here
>
Type;
};
SharedPtr<int>::Type p; // sample usage, “::Type” is ugly
What we’d really like to be able to do is simply this:
template< typename T >
typedef Loki::SmartPtr
<
T, // note, T still varies
RefCounted, // but everything else is fixed
NoChecking,
false,
PointsToOneObject,
SingleThreaded,
SimplePointer<T> // note, T can be used as here
>
SharedPtr;
SharedPtr<int> p; // sample usage, “::Type” is ugly
[...]
The workaround is ugly, and it would be good to replace it with
first-class language support that offers users a natural C++ template
syntax.
That "first-class language support" comes in the form of template aliases. We can now look at what n1499 has to say:
In this paper we will focus on describing an aliasing mechanism that
allows the two semantics mentioned in N1406 to coexist instead being
regarded as mutually exclusive. First let’s consider a toy example:
template <typename T>
class MyAlloc {/*...*/};
template <typename T, class A>
class MyVector {/*...*/};
template <typename T>
struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage
The fundamental problem with this idiom, and the main motivating fact
for this proposal, is that the idiom causes the template parameters to
appear in non-deducible context. That is, it will not be possible to
call the function foo below without explicitly specifying template
arguments.
template <typename T> void foo (Vec<T>::type&);
Also, the syntax is somewhat ugly. We would rather avoid the nested
::type call. We’d prefer something like the following:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Note that we specifically avoid the term "typedef template" and
introduce the new syntax involving the pair "using" and "=" to help
avoid confusion: we are not defining any types here, we are
introducing a synonym (i.e. alias) for an abstraction of a type-id
(i.e. type expression) involving template parameters. If the template
parameters are used in deducible contexts in the type expression then
whenever the template alias is used to form a template-id, the
values of the corresponding template parameters can be deduced – more
on this will follow. In any case, it is now possible to write generic
functions which operate on Vec<T> in deducible context, and the
syntax is improved as well. For example we could rewrite foo as:
template <typename T> void foo (Vec<T>&);
We underscore here that one of the primary reasons for proposing
template aliases was so that argument deduction and the call to
foo(p) will succeed.
So you can see that n1499 addresses the problems in n1406 as well as introducing a syntax that's much cleaner and easier to read.

typedef return type of template parameter's member function

I'm trying to typedef the return type of a member function of a template argument. So something like this:
template <typename T>
class DoSomething{
typedef return_type (T::*x)(void)const data_type;
data_type x1;
};
In this case, I want to typedef the return type of a const member function of the template parameter, called x. In this example return_type is just a place holder, just to show what I want. It won't compile.
EDIT:
The reason I want it this way is: I want to do the operations on x1 or any other variable of type data_type in this example, with the same precision as the return type of the x() member function. So if x() returns a float all my template ops will be in floats and so on.
I found one answer on SO. But I don't want to use any C++11 features. So no decltype, no auto. Just something that will work with a C++03 compiler.
This seems to work (even when Boost Typeof is forced to use the long way rather than any C++11 or compiler-specific feature):
#include <boost/utility/declval.hpp>
#include <boost/typeof/typeof.hpp>
template <typename T>
class DoSomething {
typedef BOOST_TYPEOF_TPL(boost::declval<T const&>().x()) data_type;
data_type x1;
};
But the resulting type cannot involve any class, struct, union, or enum types.
The easiest way to do this may be boost's typeof, which operates like decltype, but works in C++03.
The core idea of the typedef is the following:
typedef known_type [<modifiers>] new_type;
In this case known_type should be already defined and known. Dot. There is not other way. Based on this known existing type you can define a new type.
Start thinking from this.

Why are type_traits implemented with specialized template structs instead of constexpr?

Is there any reason why the standard specifies them as template structs instead of simple boolean constexpr?
In an additional question that will probably be answered in a good answer to the main question, how would one do enable_if stuff with the non-struct versions?
One reason is that constexpr functions can't provide a nested type member, which is useful in some meta-programming situations.
To make it clear, I'm not talking only of transformation traits (like make_unsigned) that produce types and obviously can't be made constexpr functions. All type traits provide such a nested type member, even unary type traits and binary type traits. For example is_void<int>::type is false_type.
Of course, this could be worked around with std::integral_constant<bool, the_constexpr_function_version_of_some_trait<T>()>, but it wouldn't be as practical.
In any case, if you really want function-like syntax, that is already possible. You can just use the traits constructor and take advantage of the constexpr implicit conversion in integral_constant:
static_assert(std::is_void<void>(), "void is void; who would have thunk?");
For transformation traits you can use a template alias to obtain something close to that syntax:
template <bool Condition, typename T = void>
using enable_if = typename std::enable_if<Condition, T>::type;
// usage:
// template <typename T> enable_if<is_void<T>(), int> f();
//
// make_unsigned<T> x;
Note: this ends up looking more like a rant than a proper answer... I did got some itch reading the previous answers though, so please excuse me ;)
First, class traits are historically done with template structures because they predate constexpr and decltype. Without those two, it was a bit more work to use functions, though the various library implementations of is_base_of had to use functions internally to get the inheritance right.
What are the advantages of using functions ?
inheritance just works.
syntax can be more natural (typename ::type looks stupid TM)
a good number of traits are now obsolete
Actually, inheritance is probably the main point against class traits. It's annoying as hell that you need to specialize all your derived classes to do like momma. Very annoying. With functions you just inherit the traits, and can specialize if you want to.
What are the disadvantages ?
packaging! A struct trait may embed several types/constants at once.
Of course, one could argue that this is actually annoying: specializing iterator_traits, you just so often gratuitously inherit from std::iterator_traits just to get the default. Different functions would provide this just naturally.
Could it work ?
Well, in a word where everything would be constexpr based, except from enable_if (but then, it's not a trait), you would be going:
template <typename T>
typename enable_if<std::is_integral(T()) and
std::is_signed(T())>::type
Note: I did not use std::declval here because it requires an unevaluated context (ie, sizeof or decltype mostly). So one additional requirement (not immediately visible) is that T is default constructible.
If you really want, there is a hack:
#define VALUE_OF(Type_) decltype(std::declval<T>())
template <typename T>
typename enable_if<std::is_integral(VALUE_OF(T)) and
std::is_signed(VALUE_OF(T))>::type
And what if I need a type, not a constant ?
decltype(common_type(std::declval<T>(), std::declval<U>()))
I don't see a problem either (and yes, here I use declval). But... passing types has nothing to do with constexpr; constexpr functions are useful when they return values that you are interested in. Functions that return complex types can be used, of course, but they are not constexpr and you don't use the value of the type.
And what if I need to chain trais and types ?
Ironically, this is where functions shine :)
// class version
template <typename Container>
struct iterator { typedef typename Container::iterator type; };
template <typename Container>
struct iterator<Container const> {
typedef typename Container::const_iterator type;
};
template <typename Container>
struct pointer_type {
typedef typename iterator<Container>::type::pointer_type type;
};
template <typename Container>
typename pointer_type<Container>::type front(Container& c);
// Here, have a cookie and a glass of milk for reading so far, good boy!
// Don't worry, the worse is behind you.
// function version
template <typename Container>
auto front(Container& c) -> decltype(*begin(c));
What! Cheater! There is no trait defined!
Hum... actually, that's the point. With decltype, a good number of traits have just become redundant.
DRY!
Inheritance just works!
Take a basic class hierarchy:
struct Base {};
struct Derived: Base {};
struct Rederived: Derived {};
And define a trait:
// class version
template <typename T>
struct some_trait: std::false_type {};
template <>
struct some_trait<Base>: std::true_type {};
template <>
struct some_trait<Derived>: some_trait<Base> {}; // to inherit behavior
template <>
struct some_trait<Rederived>: some_trait<Derived> {};
Note: it is intended that the trait for Derived does not state directly true or false but instead take the behavior from its ancestor. This way if the ancestor changes stance, the whole hierarchy follows automatically. Most of the times since the base functionality is provided by the ancestor, it makes sense to follow its trait. Even more so for type traits.
// function version
constexpr bool some_trait(...) { return false; }
constexpr bool some_trait(Base const&) { return true; }
Note: The use of ellipsis is intentional, this is the catch-all overload. A template function would be a better match than the other overloads (no conversion required), whereas the ellipsis is always the worst match guaranteeing it picks up only those for which no other overload is suitable.
I suppose it's unnecessary to precise how more concise the latter approach is ? Not only do you get rid of the template <> clutter, you also get inheritance for free.
Can enable_if be implemented so ?
I don't think so, unfortunately, but as I already said: this is not a trait. And the std version works nicely with constexpr because it uses a bool argument, not a type :)
So Why ?
Well, the only technical reason is that a good portion of the code already relies on a number of traits that was historically provided as types (std::numeric_limit) so consistency would dictate it.
Furthermore it makes migration from boost::is_* just so easier!
I do, personally, think it is unfortunate. But I am probably much more eager to review the existing code I wrote than the average corporation.
One reason is that the type_traits proposal is older than the constexpr proposal.
Another one is that you are allowed to add specializations for your own types, if needed.
Probably because boost already had a version of type_traits that was implemented with templates.
And we all know how much people on the standards committee copy boost.
I would say the mainreason is that type_traits was already part of tr1 and was therefore basically guaranteed to end up in the standard in more or less the same form, so it predates constexpr. Other possible reasons are:
Having the traits as types allows for overloading functions on the type of the trait
Many traits (like remove_pointer) define a type instead of a value, so they have to be expressed in this way. Having different interfaces for traits defining values and traits defining types seems unnessecary
templated structs can be partial specialized, while functions can't, so that might make the implementation of some traits easier
For your second question: As enable_if defines a type (or not, if it is passed false) a nested typedef inside a struct is really the way to go