I have some problem. What is meaning next code?
template<typename>
struct function_traits; // (1)
template<typename ClassType,
typename ReturnType,
typename... Arguments>
struct function_traits<ReturnType(ClassType::*)(Arguments...) const> { // (2)
...
};
template<typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
// (3) Why here inheritance?
Thanks!
It's understandable that you find this a mystery. Most of us do at the beginning.
First:
template<typename>
struct function_traits; // (1)
This declares the general form of a template class which has one template parameter, which is a type (class X, struct Y, int, float, std::string, whatever). Note that at present the template is declared, but no classes can be instantiated from it, because the template has no specialisations. Not even a default one.
Second:
template<typename ClassType,
typename ReturnType,
typename... Arguments>
struct function_traits<ReturnType(ClassType::*)(Arguments...) const> { // (2)
...
using result_type = ReturnType; // capture the template type into a typedef in the class namespace
};
This defines a partial specialisation of the template function_traits<typename T> where T is any member function pointer of any class which returns any return type and takes any number of arguments. Because ReturnType has been assigned a template parameter, it means that the definition of this class is allowed to refer to it as a type, thus deducing the result_type of the member function.
However, at this stage the specialisation is not useful because a caller would need to specify the complete function pointer at the call site, like this: function_traits<&SomeClass::someFunction> and dealing with overloads would be tricky.
Now the third part makes an 'interface' specialisation which says that for any class T, function_traits<T> shall be derived from function_traits<&T::operator()>.
template<typename T>
struct function_traits : public function_traits<decltype(&T::operator())> {};
// (3) Why here inheritance?
Because there is such a specific match in the template expansion, it will only be expanded for types that have a call operator (operator()). The base class is providing the return type, from the second specialisation, so this template is able to capture the return type of any type which has a call operator. Because this class is derived from the actual class that captures the return type, result_type is also part of this class's scope.
now we can write:
struct Foo {
int operator()();
};
using foo_ret = function_traits<Foo>::result_type;
And foo_ret will be int.
Still confused? Welcome to your first 6 months of template programming.
Related
I have very long parameter pack. I wonder is there any way to store the parameter pack and reuse it later. For example, if there are 2 templates:
template<class ... Types> struct A {};
template<class ... Types> struct B {};
I have a specialized type:
typedef A<int, int, float> A1_t;
Is there any operation can let me create a specialized type B which use the same parameter pack as A1_t? (B<int, int, float>). Is there any method to retrieve the <int, int, float> from A1_t or store it?
I want obtain a specialized type B1_t instead of creating the object of B1_t.
A and B describes completely different concept, so I cannot make B nested inside A.
moreover, I would also like to feed the parameter packs to specialize function templates.
template<class ...Ts>
C<Ts...> func1()
{
}
so I can directly call func1<int, int, float>()
It will be nice if I can do something like this:
template<typename T>
transform<B, T> func1()
{
}
next step would be something similar to this:
template<template<class...Ts> templ>
B<Ts...> func2(Ts ...args)
{
}
So I can do func2<A1_t>(1, 2, 3.0f) directly.
Something like this? Using a type transformation based on partial specialization:
#include<type_traits>
template<template<typename...> class, typename>
struct with_tmpl_args_of;
template<template<typename...> class OtherTmpl, template<typename...> class Tmpl, typename... Args>
struct with_tmpl_args_of<OtherTmpl, Tmpl<Args...>> {
using type = OtherTmpl<Args...>;
};
template<template<typename...> class OtherTmpl, typename T>
using with_tmpl_args_of_t = typename with_tmpl_args_of<OtherTmpl, T>::type;
// example
template<class ... Types> struct A {};
template<class ... Types> struct B {};
using A1_t = A<int, int, float>;
using B1_t = with_tmpl_args_of_t<B, A1_t>;
// test
static_assert(std::is_same_v<B1_t, B<int, int, float>>);
This is limited to class templates that do not use non-type template arguments. There is currently unfortunately no way to define template template parameters which accept both type and non-type template parameters in the same template template parameter's parameter.
Also beware of default arguments. This will not use OtherTmpl's default arguments, if one of Tmpl's default arguments matches that position in the template list and will fail if Tmpl's template list (including defaulted arguments) is larger than OtherTmpls.
Regarding the additional examples in your edit:
The second example works directly with the type transform I defined above:
template<typename T>
with_tmpl_args_of_t<B, T> func1()
{
}
The third one can be done like this:
template<typename A, typename... Ts>
with_tmpl_args_of_t<B, A> func2(Ts... args)
{
}
It guarantees that the return type has the same template arguments as A1_t, but it does accept all types as arguments, even if they don't match the types in the template arguments of A1_t. This should not usually be a problem. If the types are not convertible to the correct ones you will get an error at the point where you try the conversion.
If you must take the exact same types as in the template arguments of A1_t for function parameters, you can do something like (untested):
template<typename T>
struct func_with_tmpl_args_of;
template<template<typename...> class Tmpl, typename... Args>
struct func_with_tmpl_args_of<Tmpl<Args...>> {
template<typename F>
struct inner {
constexpr inner(F f) : f(std::move(f)) {}
constexpr static decltype(auto) operator()(Args... args) const {
return f(std::forward<Args>(args)...);
}
private:
F f;
};
};
// example
template<typename T>
constexpr inline auto func2 = func_with_tmpl_args_of<T>::inner{[](auto... args)
-> with_tmpl_args_of_t<B, T> {
// actual function body
}};
from https://github.com/wjakob/tbb/blob/master/include/tbb/tbb_allocator.h#L150
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{...}
what I understand is that this is a definition for a new class, that inherits from the Allocator type visible in that translation unit .
the part that I don't get is template<typename X> class Allocator = tbb_allocator .
according to the tbb docs the zero_allocator takes 2 inputs, the type T and how many objects of type T you need to allocate . the zero_allocator also inheriths from the tbb_allocator which in turns defaults to a "standard" malloc/free behaviour if TBB is not present when linking .
I still don't think I get that syntax, especially the template<typename X> class Allocator part .
Can you explain this syntax and what is achieving ?
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{...}
What we have:
template starts declaration of a template
it is followed by the template parameter list:
<typename T, template<typename X> class Allocator = tbb_allocator>
The first template parameter is "some type" T
the next one is not a type, it is a template itself.
template<typename X> class Allocator
So the template class zero_allocator needs to get instantiated with first
parameter is any type T and with second parameter a template which itself takes on template parameter X must be given.
In addition, the second template parameter for zero_allocator can be left, in this case for Allocator parameter the template tbb_allocator is used.
Here a full compileable example:
template <typename Y>
class ExampleTemplate {};
// and the one which is used as the default
template <typename Y>
class tbb_allocator {};
template <typename T, template<typename X> class Allocator = tbb_allocator>
class zero_allocator : public Allocator<T>
{
// Lets use the type T:
T some_var; // in our example, this will be "int some_var"
// and here we use the Template Template thing...
Allocator<float> some_allocator;
};
int main()
{
zero_allocator< int, ExampleTemplate > za;
}
I've been working on a way of producing compile-time information about classes that wrap other classes in C++. In a minimal example of the problem I am about to ask about, such a wrapper class:
contains a typedef WrappedType defining the type of the wrapped class; and
overloads a struct template called IsWrapper to indicate that it is a wrapper class.
There is a struct template called WrapperTraits that can then be used to determine the (non-wrapper) root type of a hierarchy of wrapped types. E.g. if the wrapper class is a class template called Wrapper<T>, the root type of Wrapper<Wrapper<int>> would be int.
In the code snippet below, I have implemented a recursive struct template called GetRootType<T> that defines a typedef RootType that gives the root type of wrapper type T. The given definition of WrapperTraits just contains the root type as defined by GetRootType, but in practice it would have some additional members. To test it, I have written an ordinary function f that takes an int, and an overloaded function template f that takes an arbitrary wrapper class that has int as its root type. I have used SFINAE to distinguish between them, by using std::enable_if in the function template's return type to check whether or not f's argument's root type is int (if f's argument is not a wrapper, attempting to determine its root type will fail). Before I ask my question, here is the code snippet:
#include <iostream>
#include <type_traits>
// Wrapper #######################################
template<class T>
struct Wrapper {typedef T WrappedType;};
template<class T, class Enable=void>
struct IsWrapper: std::false_type {};
template<class T>
struct IsWrapper<Wrapper<T> >: std::true_type {};
// WrapperTraits #######################################
template<
class T,
bool HasWrapper=
IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>
struct GetRootType {
static_assert(IsWrapper<T>::value,"T is not a wrapper type");
typedef typename T::WrappedType RootType;
};
template<class T>
struct GetRootType<T,true> {
typedef typename GetRootType<typename T::WrappedType>::RootType RootType;
};
template<class T>
struct WrapperTraits {
typedef typename GetRootType<T>::RootType RootType;
};
// Test function #######################################
void f(int) {
std::cout<<"int"<<std::endl;
}
// #define ROOT_TYPE_ACCESSOR WrapperTraits // <-- Causes compilation error.
#define ROOT_TYPE_ACCESSOR GetRootType // <-- Compiles without error.
template<class T>
auto f(T) ->
typename std::enable_if<
std::is_same<int,typename ROOT_TYPE_ACCESSOR<T>::RootType>::value
>::type
{
typedef typename ROOT_TYPE_ACCESSOR<T>::RootType RootType;
std::cout<<"Wrapper<...<int>...>"<<std::endl;
f(RootType());
}
int main() {
f(Wrapper<int>());
return 0;
}
This compiles correctly (try it here) and produces the output:
Wrapper<...<int>...>
int
However, I have used GetRootType to determine the root type in the call to std::enable_if. If I instead use WrapperTraits to determine the root type (you can do this by changing the definition of ROOT_TYPE_ACCESSOR), GCC produces the following error:
test.cpp: In instantiation of ‘struct WrapperTraits<int>’:
test.cpp:49:6: required by substitution of ‘template<class T> typename std::enable_if<std::is_same<int, typename WrapperTraits<T>::RootType>::value>::type f(T) [with T = int]’
test.cpp:57:15: required from ‘typename std::enable_if<std::is_same<int, typename WrapperTraits<T>::RootType>::value>::type f(T) [with T = Wrapper<int>; typename std::enable_if<std::is_same<int, typename WrapperTraits<T>::RootType>::value>::type = void]’
test.cpp:62:19: required from here
test.cpp:21:39: error: ‘int’ is not a class, struct, or union type
bool HasWrapper=IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>
My question is: what rules about argument deduction in the C++ standard explain why using WrapperTraits causes a compilation error but using GetRootType doesn't? Please note that what I want in asking this is to be able to understand why this compilation error occurs. I'm not so interested in what changes could be made to make it work, as I already know that changing the definition of WrapperTraits to this fixes the error:
template<
class T,
class Enable=typename std::enable_if<IsWrapper<T>::value>::type>
struct WrapperTraits {
typedef typename GetRootType<T>::RootType RootType;
};
template<class T>
struct WrapperTraits<T,typename std::enable_if<!IsWrapper<T>::value>::type> {
};
However, if anyone can see a more elegant way of writing f and WrapperTraits, I would be very interested in seeing it!
The first part of your question is why it fails. The answer is that on a compile-time level, && does not have short-circuit properties. This line:
bool HasWrapper=IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>
fails because the first condition is false, yet the compiler tries to instantiate the second part, but T is int and hence T::WrappedType does not work.
To answer the second part of your question on how to make it easier, I think the following should make you quite happy:
#include <iostream>
#include <type_traits>
// Wrapper #######################################
template<class T>
struct Wrapper {};
// All you need is a way to unwrap the T, right?
template<class T>
struct Unwrap { using type = T; };
template<class T>
struct Unwrap<Wrapper<T> > : Unwrap<T> {};
// Test function #######################################
void f(int) {
std::cout<<"int"<<std::endl;
}
// Split unwrapping and checking it with enable_if<>:
template<class T,class U=typename Unwrap<T>::type>
auto f(T) ->
typename std::enable_if<
std::is_same<int,U>::value
>::type
{
std::cout<<"Wrapper<...<int>...>"<<std::endl;
f(U());
}
int main() {
f(Wrapper<int>());
return 0;
}
Live example
The problem you are having is due to the fact that SFINAE only happens in the "immediate context" (a term that the standard uses, but does not define well) of a template instantiation. The instantiation of WrapperTraits<int> is in the immediate context of the instantiation of auto f<int>() -> ..., and it succeeds. Unfortunately, WrapperTraits<int> has an ill-formed member RootType. Instantiation of that member is not in the immediate context, so SFINAE does not apply.
To get this SFINAE to work as you intend, you need to arrange for WrapperTraits<int> to not have a type named RootType, instead of having such a member but with an ill-formed definition. This is why your corrected version works as intended, although you could save some repetition by reordering:
template<class T, class Enable=void>
struct WrapperTraits {};
template<class T>
struct WrapperTraits<T,typename std::enable_if<IsWrapper<T>::value>::type> {
typedef typename GetRootType<T>::RootType RootType;
};
I would probably code up the entire traits system as (DEMO):
// Plain-vanilla implementation of void_t
template<class...> struct voider { using type = void; };
template<class...Ts>
using void_t = typename voider<Ts...>::type;
// WrapperTraits #######################################
// Wrapper types specialize WrappedType to expose the type they wrap;
// a type T is a wrapper type iff the type WrappedType<T>::type exists.
template<class> struct WrappedType {};
// GetRootType unwraps any and all layers of wrappers.
template<class T, class = void>
struct GetRootType {
using type = T; // The root type of a non-WrappedType is that type itself.
};
// The root type of a WrappedType is the root type of the type that it wraps.
template<class T>
struct GetRootType<T, void_t<typename WrappedType<T>::type>> :
GetRootType<typename WrappedType<T>::type> {};
// non-WrappedTypes have no wrapper traits.
template<class T, class = void>
struct WrapperTraits {};
// WrappedTypes have two associated types:
// * WrappedType, the type that is wrapped
// * RootType, the fully-unwrapped type inside a stack of wrappers.
template<class T>
struct WrapperTraits<T, void_t<typename WrappedType<T>::type>> {
using WrappedType = typename ::WrappedType<T>::type;
using RootType = typename GetRootType<T>::type;
};
// Convenience aliases for accessing WrapperTraits
template<class T>
using WrapperWrappedType = typename WrapperTraits<T>::WrappedType;
template<class T>
using WrapperRootType = typename WrapperTraits<T>::RootType;
// Some wrappers #######################################
// Wrapper<T> is a WrappedType
template<class> struct Wrapper {};
template<class T>
struct WrappedType<Wrapper<T>> {
using type = T;
};
// A single-element array is a WrappedType
template<class T>
struct WrappedType<T[1]> {
using type = T;
};
// A single-element tuple is a WrappedType
template<class T>
struct WrappedType<std::tuple<T>> {
using type = T;
};
Although there's a lot of machinery there, and it may be more heavy-weight than you need. For example, the WrapperTraits template could probably be eliminated in favor of simply using WrappedType and GetRootType directly. I can't imagine you'll often need to pass a WrapperTraits instantiation around.
I was writing some code where I have a class that can accept mixins as variadic template parameters. However, I also need the mixins to be able to access the base class through the CRTP idiom. Here's a minimal example that cannot quite do what I want:
template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};
However, a mixin that I might pass to Foo will, in general, have several template parameters, like so:
template <class Derived, class Type1, class Type2>
class Bar
{
Derived& operator()()
{
return static_cast<Derived&>(*this);
}
};
How can I change Foo so that I can have it inherit from a number of base classes, where I control the template parameters accepted by each base class? If I hand Foo a list of template-template parameters, along with a list of arguments to pass to them, then I don't see how I would be able to associate each template-template parameter with its arguments. So far, I thought of something like this, but I don't know how I would proceed.
template <template <class...> class T,
template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
I am not quite sure I understood the problem, so please let me rephrase it so that we can start on the right foot.
You need to thread the derived type to the base classes, in a typical CRTP use case, while at the same time passing other template parameter to the various base classes.
That is, a typical base class will be:
template <typename Derived, typename X, typename Y>
struct SomeBase {
};
And you want need to create your type so that you can control the X and Y and at the same time pass the complete Derived class.
I think I would use the apply trick to generate the base class on the fly, from an adapter provided in the argument list of the Derived class.
template <typename Derived, typename X, typename Y>
struct SomeBase {};
template <typename X, typename Y>
struct SomeBaseFactory {
template <typename Derived>
struct apply { typedef SomeBase<Derived, X, Y> type; };
};
// Generic application
template <typename Fac, typename Derived>
struct apply {
typedef typename Fac::template apply<Derived>::type type;
};
Then, you would create the type as:
typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;
Where Foo is defined as:
template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};
And just because it's been a while since I trudged so deeply in templates, I checked it worked.
Of course, the Factory itself is not really a specific to a given type, so we can reuse the wrapper approach you had experimented:
template <template <typename...> class M, typename... Args>
struct Factory {
template <typename Derived>
struct apply { typedef M<Derived, Args...> type; };
};
And yes, it works too.
If I understand your question correctly, you should create template aliases that reduce each mixin to a single template parameter.
template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;
template <typename Derived>
using BazQux = Baz<Derived, Qux>;
typedef Foo<BarIntFloat, BazQux> MyFoo;
Here's a solution I came up with. There may be a more elegant way to do this, but I couldn't think of any. One caveat is that all of the mixins used need to first be nested in the wrapper struct, along with their respective arguments.
template <template <class...> class Mixin, class... Args>
struct wrapper
{
typedef Mixin<Args...> type;
};
template <class... Args>
struct test
{
};
template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{
};
template <class T>
class mixin1 {};
template <class T1, class T2>
class mixin2 {};
template <class T1, class T2, class T3>
class mixin3 {};
int main()
{
test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
return 0;
}
#void-pointer
This is basic omission of variadic templates. User cannot get i-th type from T... or get i-th value from values...
Here is a link from going native 2012 lecture by Andrei Alexandrescu:
template <typename... Ts>
void fun(const Ts&... vs) {}
• Ts is not a type; vs is not a value!
typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!
So Ts/vs should be some kind of tuple.
The following code, which attempts to specialize class template 'special', based on the return type of member function pointer types, results in a compile error with VC9:
template<class F> struct special {};
template<class C> struct special<void(C::*)()> {};
template<class R, class C> struct special<R(C::*)()> {};
struct s {};
int main()
{
special<void(s::*)()> instance;
return 0;
}
error C2752: 'special' : more than one partial specialization matches the template argument list
The same code is accepted by GCC-4.3.4, as shown by: http://ideone.com/ekWGg
Is this a bug in VC9 and if so, has this bug persisted into VC10?
I have however come up with a horrendously intrusive workaround (for this specific use case, at least. More general solutions welcome):
#include <boost/function_types/result_type.hpp>
#include <boost/type_traits/is_same.hpp>
template<typename F, typename R>
struct is_result_same :
boost::is_same<
typename boost::function_types::result_type<F>::type,
R
>
{};
template<class F, bool = is_result_same<F, void>::value>
struct special {};
template<class R, class C> struct special<R(C::*)(), true> {};
template<class R, class C> struct special<R(C::*)(), false> {};
This is a bug.
template <class C> struct special<void(C::*)()>; // specialization 1
template <class R, class C> struct special<R(C::*)()>; // specialization 2
According to 14.5.4.2, the partial ordering of these two class template specializations are the same as the partial ordering of these imaginary function templates:
template <class C> void f(special<void(C::*)()>); // func-template 3
template <class R, class C> void f(special<R(C::*)()>); // func-template 4
According to 14.5.5.2, the partial ordering of these two function templates is determined by substituting invented types for each type template parameter in the argument list of one and attempting template argument deduction using that argument list in the other function template.
// Rewrite the function templates with different names -
// template argument deduction does not involve overload resolution.
template <class C> void f3(special<void(C::*)()>);
template <class R, class C> void f4(special<R(C::*)()>);
struct ty5 {}; struct ty6 {}; struct ty7 {};
typedef special<void(ty5::*)()> arg3;
typedef special<ty6 (ty7::*)()> arg4;
// compiler internally tests whether these are well-formed and
// the resulting parameter conversion sequences are "exact":
f3(arg4());
f4(arg3());
The details of template argument deduction are in 14.8.2. Among the valid deductions are from template_name<dependent_type> and dependent_type1 (dependent_type2::*)(arg_list). So the f4(arg3()) deduction succeeds, deducing f4<void,ty5>(arg3());. The f3(arg4()) deduction can obviously never succeed, since void and ty6 do not unify.
Therefore function template 3 is more specialized than function template 4. And class template specialization 1 is more specialized than class template specialization 2. So although special<void(s::*)()> matches both specializations, it unambiguously instantiates specialization 1.