Consider the following code:
template<typename>
struct S { };
template<typename, typename>
struct B;
template <typename R, typename... Args, template<class> class C>
struct B<R(Args...), C<R>> {
void f() { }
};
int main() {
B<void(), S<void>> b;
b.f();
}
It compiles and has no problem.
Anyway, whenever one decides to use B, it has to provide two types.
What I'd like to achieve is to default somehow the second parameter (I know, partial specializations do not accept a default for their parameters) and let an user define it's type as B<void()> instead of B<void(), S<void>>.
Unfortunately, because of template template, partial specialization and the dependency existent between the parameters, all together they lead to a puzzle against which I'm struggling since a couple of hours.
Is there any clever solution to do that?
So far, I have been able to solve it with intermediate structures, but I don't like it so much...
Partial specializations don't accept default parameters, but the primary does. You can just add it there:
template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;
Then all you need to do is implement a return type metafunction for a signature. Something like:
template <class Sig>
struct return_type;
template <class Sig>
using return_type_t = typename return_type<Sig>::type;
template <class R, class... Args>
struct return_type<R(Args...)> {
using type = R;
};
You may create an helper class for that:
template <typename T> struct default_arg;
template <typename R, typename... Args>
struct default_arg<R(Args...)>
{
using type = S<R>;
};
template<typename Sign, typename T = typename default_arg<Sign>::type>
struct B;
Demo
Here we change B into a template alias.
B_t does the default arg work.
B_impl is the implementation of B without any default args.
B is a using alias that gets the result of B_t.
template<class> struct S {};
template<class, class>
struct B_impl;
template<class R, class... Args, template<class...> class C>
struct B_impl<R(Args...), C<R>> {
void f() { }
};
template<class, class=void>
struct B_t;
template<class R, class...Args>
struct B_t<R(Args...), void>:
B_t<R(Args...),S<R>>
{};
template<class R, class... Args, template<class...> class C>
struct B_t<R(Args...), C<R>> {
using type=B_impl<R(Args...), C<R>>;
};
template<class Sig, class Z=void>
using B=typename B_t<Sig,Z>::type;
The downside is that pattern-matching on B won't work well.
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,
template<typename T> struct S {};
template<typename T> struct R {};
int main() {
typedef S<double> s1;
typedef S<int> s2;
typedef R<int> s3;
static_assert(xxx<s1, s2>::value,
"No, assertion must not be raised");
static_assert(xxx<s2, s3>::value,
"Yes, assertion must be raised");
}
So, I want xxx<s1, s2>::value to return true while xxx<s2, s3>::value to return false during compile-time.
Is the existence of xxx impossible in C++?
Or, is the existence of xxx theoretically possible in C++ but possibly no one has done it yet?
Use two specialisations​ that use template template parameters to perform this "matching":
template<
typename T,
typename V>
struct xxx;
template<
template <class> class A,
template <class> class B,
typename X,
typename Y>
struct xxx<A<X>, B<Y>> {
static constexpr const int value = false;
};
template<
template <class> class U,
typename X,
typename Y>
struct xxx<U<X>, U<Y>> {
static constexpr const int value = true;
};
With your code on ideone
Note: For it to be a real type trait you should not set value manually, but derive from std::integral_constant (std::true_type or std::false_type). Above is just a quick mockup I did on my phone.
Something like same_base_template:
#include <type_traits>
template<class A, class B>
struct same_base_template : std::false_type{};
template<template<class...> class S, class... U, class... V>
struct same_base_template<S<U...>, S<V...>> : std::true_type{};
Edit:
And a third specialization since you are using non-type template arguments (std::ratio):
template<class T, template<T...> class S, T... U, T... V>
struct same_base_template<S<U...>, S<V...>> : std::true_type{};
Demo
This uses true_typeand false_type from type_traits so we don't need to write a constexpr bool value ourselves. I used a variadic template here because it was slightly more generic and took only a few more keystrokes to do. For your specific use case, you don't need them)
Is anyone knows how to declare generalized template form for the next template specialization:
template <template <class> class Container,
class Value,
class Return,
Return (Container<Value>::*Apply)(const Value &)>
class Example<Container<Value>, Apply>
{
};
Apply must be a pointer to a member function whoes signature is unknown in template declaration.
Do you mean something like this?
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
As an example:
template<typename... U>
struct T {
int f(int, char) { return 42; }
};
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
int main() {
S<T<int, char>, int(int, char)>::Apply apply = &T<int, char>::f;
}
Pretty ugly, indeed, but that's what the OP (maybe) asked.
Given the following class:
template <class T, template <typename> class B>
class A { B<T> b; };
I can now write code like such:
A<float, MyVector> a1;
A<int, MySet> a2;
What is the most elegant way to put multi-parameter classes of which all parameters are specified except one, in B? Like a map with int-keys? The only thing I can come up with is this:
template <class U> using C = MyMap<int, U>;
A<float, C<int>> a3;
Is there such a template equivalent to std::bind, where we can provide only a part of the parameters and leave one of them open? I'm quite sure the language doesn't provide for this, but people must've solved this before.
A<float, MyMap<int, _>> a3;
There isn't a built-in template equivalent to std::bind, but you can write one yourself. Here's a simple version which binds the first template argument which you could extend to suit your needs:
template <typename T, template <typename...> class B>
struct bind_t1 {
template <typename... Ts>
using type = B<T,Ts...>;
};
Then you just use bind_t1 like so:
A<float, bind_t1<int, std::map>::type> a3;
Note that for your example, you'll need to modify your template parameters to take a variadic template template:
template <class T, template <typename...> class B>
class A { B<T> b; };
Here's a slightly extended version which can bind a number of contiguous elements at the start of the parameter list:
template <template <typename...> class B, typename... Ts>
struct bind_nt1 {
template <typename... Us>
using type = B<Ts...,Us...>;
};
//Usage
A<std::less<int>, bind_nt1<std::map, int, float>::type> a3;
Here's a generic version based on the way std::bind does things. It doesn't do any validation and probably has some edge cases, but it's a good starting point. Thanks to Piotr Skotnicki for improvements.
template <std::size_t N>
struct placeholder{};
template <template <typename...> class B, typename... Ts>
struct bind_t {
private:
template <typename T, typename UTuple>
struct resolve_placeholder {
using type = T;
};
template <std::size_t N, typename UTuple>
struct resolve_placeholder<placeholder<N>, UTuple> {
using type = typename std::tuple_element<N-1, UTuple>::type;
};
public:
template <typename... Us>
using type = B<typename resolve_placeholder<Ts, std::tuple<Us...>>::type...>;
};
//Usage
A<int, bind_t<std::map, float, placeholder<1>, std::less<float>>::type> a3;
Using this, you can even change the order of template parameters:
//std::map<int,float>
bind_t<std::map, placeholder<2>, placeholder<1>>::type<float, int> b;
Suppose I have some template classes defined as follows
template<template<class>class...>
struct my_class;
template<class>
struct define_template{
template<class>
class type;
};
I need to define an alias template that substitutes define_template::type into my_class
so for three classes I could do this
template<class A, class B, class C>
using my_alias = my_class< define_template<A>::template type,
define_template<B>::template type,
define_template<C>::template type>;
I can't work out the syntax to do this for a variadic template ideally something like this
template<class... T>
using new_class = my_class<define_template<T>::template type...>;
which gives me an error "parameter packs not expanded with '...'
Does anybody know the correct synax?
From the comments below it compiles in clang, I'm using gcc 4.8.2 through Cygwin.
I'm assuming it's a bug in gcc so I've done a workaround for now
// partially specializes a template
template<template<class, class>class TT, class T>
struct TemplateBind{
template<class S>
using type = TT<T, S>;
};
// the workaround
template<template<template<class>class...>class A,
template<class, class>class B,
template<class>class... C>
class workaround {
template<class D, class... E>
static auto get_type(D, E...)
-> typename workaround<A, B, C..., TemplateBind<B, D>::template type>::template type<E...>;
static auto get_type()
->A<C...>;
public:
template<class... T>
using type = decltype(get_type(std::declval<T>()...));
};
// convinience alias
template<template<template<class>class...>class OriginalTemplate,
template<class, class>class Substitution,
class... Types>
using InstatiateVariadicTemplateTemplate = typename workaround<OriginalTemplate, Substitution>::template type<Types...>;
Then we can define a wrapper for define_template
// wrapper alias gets define_template in the right form
template<class A, class B>
using my_wrapper = typename define_template<A>::template type<B>;
and instantiate as follows
template<class... T>
using my_alias = InstatiateVariadicTemplateTemplate<my_class, my_wrapper, T...>;