I have created a class than inherit from std::tuple as:
template<class, class>
struct tuple_prepend;
template<class T, class ...Ts>
struct tuple_prepend<T, std::tuple<Ts...>>
{
using type = std::tuple<T, Ts...>;
};
template<class ...Ts>
struct tuple_optional_impl;
template<class T, class ...Ts>
struct tuple_optional_impl<T, Ts...>
{
using type = typename tuple_prepend<std::optional<T>, typename tuple_optional_impl<Ts...>::type>::type;
};
template<class T>
struct tuple_optional_impl<T>
{
using type = std::tuple<std::optional<T>>;
};
template<class ...Ts>
struct tuple_optional;
template<class ...Ts>
struct tuple_optional<std::tuple<Ts...>>
{
using type = typename tuple_optional_impl<Ts...>::type;
};
template<class ...Ts>
class Tuple : public tuple_optional<std::tuple<Ts...>>::type
{
};
tuple_optional: convert an std::tuple<T> into std::tuple<std::optional<T>> and have the same behavior with Ts....
I would like to make a custom std::get<T> to handle Tuple, I have this implementation:
namespace std
{
template<class T, class ...Ts>
std::optional<T> get(Tuple<Ts...> &_tuple) noexcept
{
return std::get<std::optional<T>>(static_cast<tuple_optional<std::tuple<Ts...>>::type>(_tuple));
}
}
But the static_cast generate this error:
error C2100: illegal indirection
message : see the reference at the instanciation of model: 'std::optionalecs::comp::HitBox std::getecs::comp::HitBox,ecs::comp::Stat,ecs::comp::Position,ecs::comp::HitBox,ecs::comp::Rotation,ecs::comp::Id(Tupleecs::comp::Stat,ecs::comp::Position,ecs::comp::HitBox,ecs::comp::Rotation,ecs::comp::Id &) noexcept' at compilation
I don't wan't to use an alias or erase the inheritance.
You don't need any of that.
template<class ...Ts> using Tuple = std::tuple<std::optional<Ts>...>;
Related
I have the following structs:
template<typename T1, typename T2>
struct A {};
template<typename T>
struct B {};
template<typename A, typename B>
struct C {};
and want to use them as follows:
C<B<int>, A<double, B<int>>> c;
Is there any way to deduce the second template parameter for A, such that I can use it like this?
C<B<int>, A<double>> c;
This should work for any template arguments of C and not just for a particular one (therefore default arguments don't seem to work).
Furthermore a solution for variadic templates would be even better, so instead of
C<B<int>, A<double, B<int>>, A<float, A<double, B<int>>>> c;
something like this would be nice:
C<B<int>, A<double>, A<float>> c;
With a bit of template metaprogramming fun, I was able to solve your problem both for the two-parameter and the variadic case (although in a somewhat narrow way):
// TypeList stuff
template<class... Args>
struct List {
template<class Arg>
using Add = List<Args..., Arg>;
};
template<class List> struct TailI;
template<class A, class... Ar> struct TailI<List<A, Ar...>> {
using type = typename TailI<List<Ar...>>::type;
};
template<class A> struct TailI<List<A>> {
using type = A;
};
template<class List>
using Tail = typename TailI<List>::type;
template<template<class...> class OP, class List> struct rename_impl;
template<template<class...> class OP, class... ListArgs>
struct rename_impl<OP, List<ListArgs...>> {
using type = OP<ListArgs...>;
};
template<template<class...> class OP, class List>
using rename = typename rename_impl<OP, List>::type;
// Actual code solving problem at hand
template<class T1, class T2> struct A{};
template<class... Args> struct C{};
template<class Built, class Next, class... Rest>
struct builder {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = typename builder<NewBuilt, Rest...>::type;
};
template<class Built, class Next>
struct builder<Built, Next> {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = rename<C, NewBuilt>;
};
template<class First, class... Rest>
using c_builder = typename builder<List<First>, Rest...>::type;
using t = c_builder<int, double, float>;
// Test driver
#include <utility>
static_assert(std::is_same_v<t, C<int, A<double, int>, A<float, A<double, int>>>>, "");
For the simpler case of
template<typename A, typename B> struct C {};
you can use a helper class to provide you the type you need.
template<typename T1, typename T2>
struct C_Helper
{
using type = C<B<T1>, A<T2, B<T1>>>;
};
and use
using C_Type = typename C_Helper<int, double>::type;
C_Type c;
I haven't thought through how that can be extended to support a variadic class template C,
I'm trying to implement compile-time configurable callback for sync/async call behaviour.
Here is the first approach to do that:
//emit type's
enum EEmitType
{
SYNC,
ASYNC,
};
//general
template<EEmitType et, typename... Args>
class callback_impl;
//implementation
template<EEmitType et, typename R, typename... Args>
class callback_impl<et, R(Args...)>
{ /*todo*/ };
//................................................................
//convert enum value to type or SFINAE
template <EEmitType et>
using callback_emit_type = std::integral_constant<EEmitType, et>;
//(for default SYNC)
template <typename T>
struct is_emit_type : std::false_type {};
//(for any other implementation)
template <EEmitType et>
struct is_emit_type<callback_emit_type<et>> : std::true_type {};
//................................................................
//metafunction
template <typename T>
using is_emit_type_t = typename is_emit_type<T>::type;
//................................................................
//for decl. like: callback<void()>
template <typename _unused, typename... Args>
struct construct_callback_impl
{
//alias on implementation
using type = callback_impl<SYNC, Args...>;
};
//for decl. like: callback<callback_emit_type<ASYNC>, void()>
template <typename EEmitType, typename... Args>
struct construct_callback_impl<typename
std::enable_if<is_emit_type_t<EEmitType>::value>::type, EEmitType, Args...>
{
//alias on implementation
using type = callback_impl<EEmitType::value, Args...>;
};
//................................................................
//user alias
template <typename... Args>
using callback = typename construct_callback_impl<Args...>::type;
Now USING:
callback<int(int)> ff_s; //<-- uses undefined class 'callback_impl<SYNC>'
callback<callback_emit_type<ASYNC>, int(int)> ff_a; //<--OK
Of course because first args is eating, and for success compilation it should be write down like:
callback<int(int), int(int)> ff_s
But of course it's not unacceptable.
OK, then I try extract EEmitType from Args...
//for decl. like: callback<void()>
template <typename... Args>
struct construct_callback_impl
{
//alias on implementation
using type = int; //temporary stub
};
//for decl. like: callback<callback_emit_type<ASYNC>, void()>
template <typename... Args>
struct construct_callback_impl<typename std::enable_if<is_emit_type_t< typename std::tuple_element_t<0, std::tuple<Args...> >::type >::value>::type, Args...>
{
//alias on implementation
using type = int; //temporary stub
};
BUT now I get the:
error C2338: tuple index out of bounds
note: see reference to class template instantiation 'std::tuple_element<0,std::tuple<>>' being compiled
Something like this should work
template <typename>
struct emit_type_value : std::integral_constant<EEmitType, SYNC> {};
template <EEmitType x>
struct emit_type_value<callback_emit_type<x>> : std::integral_constant<EEmitType, x> {};
//for decl. like: callback<void()>
template <typename Arg0, typename ... Args>
struct construct_callback_impl
{
//alias on implementation
using type = std::conditional_t<is_emit_type<Arg0>::value,
callback_impl<emit_type_value<Arg0>::value, Args...>,
callback_impl<SYNC, Arg0, Args...>>;
};
It would be somewhat terser if you just used false and true instead of SYNC and ASYNC.
Please consider the following code snippet:
template<typename T, class Tuple>
class vector
{
using size_type = typename Tuple::size_type;
template<typename... Elements,
typename = decltype(std::declval<Tuple>().reserve(size_type()))>
typename = decltype(std::declval<Tuple>().push_back(T())),
vector(Elements&&... elements)
{ /* ... */ }
};
I want to define a nested struct supports_reserve_push_back which is derived from std::true_type whenever the constructor above would be enabled (and which is derived from std::false_type in the other case).
How can I do this?
I've modified the code to make it build. And implemented the trait you requested, to the best of my understanding.
#include <iostream>
#include <type_traits>
#include <vector>
#include <map>
namespace example {
template<typename...>
using void_t = void;
template<typename T, class Tuple>
struct vector {
using size_type = typename Tuple::size_type;
using tuple_type = Tuple;
using elem_type = T;
template<typename... Elements>
vector(Elements&&... elements)
{ /* ... */ }
};
template <class T, typename = void>
struct supports_reserve_push_back : std::false_type {};
template <class Vec>
struct supports_reserve_push_back<Vec, void_t<
decltype(std::declval<typename Vec::tuple_type>().reserve(typename Vec::size_type())),
decltype(std::declval<typename Vec::tuple_type>().push_back(typename Vec::elem_type())) >
>
: std::true_type {};
}
int main() {
std::cout
<< example::supports_reserve_push_back<example::vector<int, std::vector<int>>>::value
<< '\n'
<< example::supports_reserve_push_back<example::vector<int, std::map<int, int>>>::value;
return 0;
}
A few thing to note:
The way you wrote the c'tor originally caused a hard error when instantiating the class in the negative case. That's why I removed the chcck from the c'tor.
I'd suggest you define the type traits first, and use them to enable your c'tors.
namespace details{
template<template<class...>class Z,class,class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z,class...Ts>
struct can_apply<Z,std::void_t<Z<Ts...>,Ts...>:
std::true_type{};
}
template<template<class...>class Z,class... Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
Wrap up your decltypes into template usings and do some && and done.
There is also a std experimental similar to above.
template<class T, class U>
using push_back_r = decltype(std::declval<T>().push_back(std::declval<U>()));
template<class T>
using reserve_r = decltype(std::declval<T>().reserve(1));
template<class T, class U>
constexpr can_apply<push_back_r,T,U> has_push_back={};
template<class T>
constexpr can_apply<reserve_r,T> has_reserve={};
template<bool b>using bool_t=std::integral_constant<bool,b>;
template<class T,class U>
constexpr bool_t<has_push_back<T,U>&&has_reserve<T>>
efficiently_fillable_with = {};
Then efficiently_fillable_with<T,U> is true type iff you can reserve space with T and then push Us into it. The r/l value category of T and U is preserved: if you want to know about filling an non-cinstant lvalue of T with rvalue Us:
efficiently_fillable_with<T&,U>
If you want to fill with U const& instead of rvalues, pass U const&.
#include <type_traits>
#include <utility>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void_t<>, Operation, Args...>;
template <typename T, typename Sz>
using has_reserve = decltype(std::declval<T>().reserve(std::declval<Sz>()));
template <typename T, typename U>
using has_push_back = decltype(std::declval<T>().push_back(std::declval<U>()));
template <typename Tuple, typename T, typename size_type>
constexpr bool supports_reserve_push_back = detect<has_reserve, Tuple, size_type>{} && detect<has_push_back, Tuple, T>{};
Test:
template <typename T, class Tuple>
class vector
{
public:
using size_type = typename Tuple::size_type;
template <typename... Elements, typename U = Tuple,
std::enable_if_t<supports_reserve_push_back<U&, T, size_type>, int> = 0>
vector(Elements&&... elements)
{
}
template <typename... Elements, typename U = Tuple,
std::enable_if_t<!supports_reserve_push_back<U&, T, size_type>, int> = 0>
vector(Elements&&... elements)
{
}
};
DEMO
I would try the following approach:
Have your vector template class inherit from a superclass, like this:
template<typename T, class Tuple> class vector
: public supports_reserve_push_back_impl<
vector_has_default_constructor<T, Tuple>::value() > {
// ...
}
Now, define a vector_has_default_constructor template class that takes the same template parameters:
template<typename T, class Tuple> class vector_has_default_constructor {
public:
// ...
};
In vector_has_default_constructor:
Define a constexpr bool value() method with the same exact signature as the vector's constructor. This constexpr method returns true.
Define an overload constexpr bool value() with a ... signature, which should have lower priority in the overload resolution. This constexpr returns false.
Now, this situation is reduced to defining two trivial specializations, supports_reserve_push_back_impl<true> and supports_reserve_push_back_impl<false>.
supports_reserve_push_back_impl<true> contains your desired supports_reserve_push_back value, and is inherited by your vector.
supports_reserve_push_back_impl<false> is empty.
I really wanted to solve this myself, but spending hours looking at the same code again and again is not making me happy. The error message looks quite straightforward, and it points me to the Not2 template. It complains that there is no Apply member, but it clearly has Apply, two of them. Function2 and Not2 has a very similar form, but the compiler doesn't say anything about Function2, so something's going wrong inside Not2. Not2 is meant to take a Function2 template and negate the result.
I removed irrelevant code as much as possible, but still the code seems quite long. Just skip away if you think reading all that isn't worth your time.
main.cpp:130:24: error: type/value mismatch at argument 1 in template parameter list for 'template<class T> constexpr const int unbox<T>'
using Apply = Box<!unbox<T::template Apply<U>::template Apply<V>>>;
^
main.cpp:130:24: note: expected a type, got 'typename T::Apply<U>::Apply<V>'
main.cpp:130:70: error: template argument 1 is invalid
using Apply = Box<!unbox<T::template Apply<U>::template Apply<V>>>;
^
main.cpp: In instantiation of 'struct Sort_<List<Box<2>, Box<1> > >':
main.cpp:155:37: required by substitution of 'template<class T> using Sort = typename Sort_::Type [with T = List<Box<2>, Box<1> >]'
main.cpp:159:38: required from here
main.cpp:151:77: error: no class template named 'Apply' in 'Not2<Function2<LessThan_> >::Apply<Box<2> > {aka struct Not2<Function2<LessThan_> >::Apply_<Box<2> >}'
Filter<Tail<T>, Not2<LessThan>::template Apply<Head<T>>::template Apply>> Type;
^
template<int n>
struct Box
{
};
template<typename T>
struct Unbox_;
template<int n>
struct Unbox_<Box<n>>
{
static constexpr int value = n;
};
template<typename T>
constexpr int unbox = Unbox_<T>::value;
template<typename ...>
struct List
{
};
template<>
struct List<>
{
};
template<typename, typename>
struct Cons_;
template<typename T, typename ...Ts>
struct Cons_<T, List<Ts...>>
{
typedef List<T, Ts...> Type;
};
template<typename T, typename U>
using Cons = typename Cons_<T, U>::Type;
template<typename>
struct Head_;
template<typename T, typename ...Ts>
struct Head_<List<T, Ts...>>
{
typedef T Type;
};
template<typename T>
using Head = typename Head_<T>::Type;
template<typename>
struct Tail_;
template<typename T, typename ...Ts>
struct Tail_<List<T, Ts...>>
{
typedef List<Ts...> Type;
};
template<typename T>
using Tail = typename Tail_<T>::Type;
template<typename T, typename U>
struct Merge_
{
typedef Cons<Head<T>, typename Merge_<Tail<T>, U>::Type> Type;
};
template<typename T>
struct Merge_<List<>, T>
{
typedef T Type;
};
template<typename T, typename U>
using Merge = typename Merge_<T, U>::Type;
template<typename, typename T, typename>
struct If_
{
typedef T Type;
};
template<typename T, typename U>
struct If_<Box<0>, T, U>
{
typedef U Type;
};
template<typename T, typename U, typename V>
using If = typename If_<T, U, V>::Type;
template<typename T, template<typename> class U>
struct Filter_
{
typedef If<U<Head<T>>, Cons<Head<T>, typename Filter_<Tail<T>, U>::Type>,
typename Filter_<Tail<T>, U>::Type> Type;
};
template<template<typename> class T>
struct Filter_<List<>, T>
{
typedef List<> Type;
};
template<typename T, template<typename> class U>
using Filter = typename Filter_<T, U>::Type;
template<template<typename, typename> class T>
struct Function2
{
template<typename U>
struct Apply_
{
template<typename V>
using Apply = T<U, V>;
};
template<typename U>
using Apply = Apply_<U>;
};
template<typename T>
struct Not2
{
template<typename U>
struct Apply_
{
template<typename V>
using Apply = Box<!unbox<T::template Apply<U>::template Apply<V>>>;
};
template<typename U>
using Apply = Apply_<U>;
};
template<typename T, typename U>
struct LessThan_2
{
typedef Box<unbox<T> < unbox<U>> Type;
};
template<typename T, typename U>
using LessThan_ = typename LessThan_2<T, U>::Type;
using LessThan = Function2<LessThan_>;
template<typename T>
struct Sort_
{
typedef Merge<Merge<Filter<Tail<T>, LessThan::Apply<Head<T>>::template Apply>, List<Head<T>>>,
Filter<Tail<T>, Not2<LessThan>::template Apply<Head<T>>::template Apply>> Type;
};
template<typename T>
using Sort = typename Sort_<T>::Type;
int main()
{
typedef Sort<List<Box<2>, Box<1>>> L;
}
I believe you are simply missing a typename inside the unbox template argument list on the line (130) giving you the error.
Also, you do not seem to be doing any sorting in your Sort_ and Merge_ templates, since they simply concatenate lists using the head as pivot Coliru illustration. I guess your code is not completed yet.
I would like to write something like this:
template <class T>
using MyTypeOrTupple = typename std::conditional<has_member_type_MyType<T>::value,
typename T::MyType,
std::tuple<> >::type;
I implemented has_member_type_MyType using https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector
However, GCC (4.8.4) still complains about using T::MyType when MyType is not defined in T. Is there a way to solve this?
Do not use that crazy thing from Wikibooks.
template <class T>
using MyType_t = typename T::MyType;
template<class T>
using MyTypeOrTuple = detected_or_t<std::tuple<>, MyType_t, T>;
Where detected_or_t is std::experimental::detected_or_t from library fundamentals TS v2, and can be implemented as follows:
namespace detail {
template<class...> struct voidify { using type = void; };
template<class...Ts> using void_t = typename voidify<Ts...>::type;
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template< class Default, template<class...> class Op, class... Args >
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <typename...>
struct voider { using type = void; };
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename, typename = void_t<>>
struct MyTypeOrTupple { using type = std::tuple<>; };
template <typename T>
struct MyTypeOrTupple<T, void_t<typename T::MyType>> { using type = typename T::MyType; };
template <typename T>
using MyTypeOrTupple_t = typename MyTypeOrTupple<T>::type;
DEMO
I think it's required 2 level of indirection:
template<typename ...>
struct void_type
{
using type = void;
};
template<typename ...T>
using void_t = typename void_type<T...>::type;
#define HAS_TYPE(NAME) \
template<typename, typename = void> \
struct has_type_##NAME: std::false_type \
{}; \
template<typename T> \
struct has_type_##NAME<T, void_t<typename T::NAME>>: std::true_type \
{}
HAS_TYPE(MyType);
template<typename T, bool = has_type_MyType<T>::value>
struct MyTypeOrTupple_impl;
template<typename T>
struct MyTypeOrTupple_impl<T, true>
{ using type = typename T::MyType; };
template<typename T>
struct MyTypeOrTupple_impl<T, false>
{ using type = std::tuple<>; };
template<typename T> using MyTypeOrTupple = typename MyTypeOrTupple_impl<T>::type;
DEMO
Version keeping std::conditional:
template <typename T> struct identity { using type = T; };
template <typename T> struct MyType { using type = typename T::MyType; };
template <class T>
using MyTypeOrTupple =
typename std::conditional<has_member_type_MyType<T>::value,
MyType<T>,
identity<std::tuple<>>>::type::type;