I want to check if a class is a template specialization of another one. What I have tried is:
template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};
template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};
It works fine when all template parameters are type arguments but not when some are non-type arguments. For example it works with std::vector but not std::array (since the later accepts an non-type argument std::size_t).
It's important that the check is made at compile time. Also the solution must work for any template, not just vectors or arrays. That means that it can be any number of type arguments and any number of non-type arguments. For example it should work with template <class A, bool B, class C, int D, class... Args> class foo;
C++20 is a weird, weird world. Cross-checking is welcome as I'm a beginner with CTAD and not entirely sure I've covered all bases.
This solution uses SFINAE to check whether class template argument deduction (CTAD) succeeds between the requested class template and the mystery type. An additional is_same check is performed to prevent against unwanted conversions.
template <auto f>
struct is_specialization_of {
private:
template <class T>
static auto value_impl(int) -> std::is_same<T, decltype(f.template operator()<T>())>;
template <class T>
static auto value_impl(...) -> std::false_type;
public:
template <class T>
static constexpr bool value = decltype(value_impl<T>(0))::value;
};
// To replace std::declval which yields T&&
template <class T>
T declrval();
#define is_specialization_of(...) \
is_specialization_of<[]<class T>() -> decltype(__VA_ARGS__(declrval<T>())) { }>::value
// Usage
static_assert(is_specialization_of(std::array)<std::array<int, 4>>);
First caveat: Since we can't declare a parameter for the class template in any way without knowing its arguments, passing it around to where CTAD will be performed can only be done by jumping through some hoops. C++20 constexpr and template-friendly lambdas help a lot here, but the syntax is a mouthful, hence the helper macro.
Second caveat: this only works with movable types, as CTAD only works on object declarations, not reference declarations. Maybe a future proposal will allow things such as std::array &arr = t;, and then this will be fixed!
Actually fixed by remembering that C++17 has guaranteed copy-elision, which allows direct-initialization from a non-movable rvalue as is the case here!
Related
I would like to define a template class MyClass where the template parameters must be specializations of specific template classes. In this example, I would like MyClass to be a template class that accepts for its first template parameter a specialization of A and for its second template parameter a specialization of B. I may then instantiate this class as follows:
MyClass<A<int, int>, B<double, int>>;
Now, you might say, "just take the arguments of A and B as the template parameters of MyClass". Unfortunately, in my situation, A and B are both variadic templates, and so it won't be possible in the parameter list for MyClass to find the end of the template arguments for A and the beginning of the template arguments for B.
Examples of A and B follow:
template <typename... Args>
class A{
public:
A(){}
};
template <typename... Args>
class B{
public:
B(){}
};
I have found older answers that provide solutions like using SFINAE. My understanding is that, unfortunately, SFINAE has drawbacks like disabling type deduction; I tend to avoid it. My question is this: are there newer language features that allow me to get the behavior I want without SFINAE?
To give you a bit better idea of what I am imagining for MyClass, I provide this bad example below:
template <template<typename... Args> class A, typename... Args1, template<typename... Args> class B, typename... Args2>
class MyClass { // use A<Args1...> and B<Args2...> in here
public:
MyClass() {}
}; // fails because template parameter pack Args1 is not at the end of the parameter list
An alternative to SFINAE are C++20 constraints and concepts. In your case - regardless of SFINAE or concepts - the key problem will be the template parameter packs, as the standard dictates
A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list ([dcl.fct]) of the function template or has a default argument ([temp.deduct]). A template parameter of a deduction guide template ([temp.deduct.guide]) that does not have a default argument shall be deducible from the parameter-type-list of the deduction guide template.
This means that you can't have something like
template <template<typename...> class A, typename... Args1, template<typename...> class B, typename... Args2>
class MyClass {
public:
MyClass() {}
};
directly.
One possible solution is to not have a template template class at all and make sure implicitly (e.g. by a function call to a properly overloaded function) that the template arguments are correct. You could actually formalise #cigien's approach with concepts and further remove the requirement of default-constructability by using std::declval:
Introduce two functions that can only be called by objects of type A and B respectively:
template <typename... Args>
void a(A<Args...>) {}
template <typename... Args>
void b(B<Args...>) {}
Define two concepts which require that an overload of the corresponding function exists that can be called with a value of the corresponding type by using std::declval instead of the default-constructor:
template <typename T>
concept is_A = requires { a(std::declval<T>()); };
template <typename T>
concept is_B = requires { b(std::declval<T>()); };
Finally enforce the corresponding concepts on your template parameters as follows:
template <is_A A, is_B B>
class MyClass {
public:
MyClass() {}
};
With this approach the class can be default-constructed with
MyClass<A<int,int>, B<double,int>> my_class{};
Contrary to #cigien's version this does not require A and B to be default-constructible!
Try it here
Depending on your planned usage you could also use the template argument deduction when the constructor is called but be aware that then the class itself will not distinguish between different variadic template arguments (meaning std::is_same will actually return true for two different parameter packs), only the constructor will. Furthermore the class won't be default constructable anymore and you would have to call it with
MyClass my_class{A<int,int>{}, B<int,double>{}};
One way would be to not template the class at all and template the constructor with two template parameter packs
class MyClass {
public:
template <typename... Args1, typename... Args2>
MyClass(A<Args1...>, B<Args2...>) {}
};
Try it here
You could make this more flexible by introducing the concepts
template <template<typename...> class T, typename... Ts>
concept is_A = std::is_same_v<A<Ts...>,T<Ts...>>;
template <template<typename...> class T, typename... Ts>
concept is_B = std::is_same_v<B<Ts...>,T<Ts...>>;
(or alternatively with std::is_base_of instead), templating the class without specifying the variadic template parameters and then making the constructor templated as well with two template parameter packs that can be deducted from the input arguments
template <template<typename...> class C1, template<typename...> class C2>
requires is_A<C1> && is_B<C2>
class MyClass {
public:
template <typename... Args1, typename... Args2>
requires is_A<C1,Args1...> && is_B<C2,Args2...>
MyClass(C1<Args1...>, C2<Args2...>) {}
};
and add a requires clause to the class and/or constructor.
Try it here.
The given constraints could of course also be enforced with SFINAE std::enable_if_t instead of concepts. For an example of this see e.g. here.
I don't believe this is possible by specializing class templates, but you can work around this by using function template argument deduction, which can distinguish between multiple parameter packs
template <typename... Args1, typename... Args2>
void f(A<Args1...>, B<Args2...>) {}
This function will be matched when passed instantiations of A and B, which we use as the true case.
For the false case, we can just match anything and delete it
template <typename... Ts>
void f(Ts...) = delete;
Now, you can have MyClass take 2 type parameters, and call f, say in the constructor, to make sure the parameters are instantiations of A and B.
template<typename T, typename U>
class MyClass {
public:
MyClass()
{
f(T{}, U{}); // hard error if not called with specializations of A and B
}
};
This will essentially assert that the types satisfy the constraints you want, but you can further extract the arguments of A and B if you want to use them as well.
Here's a demo.
I'm attempting to make an std::function alternative that supports optional arguments with defaults. I tried a few different syntactical ideas, but the most realistic seems to be a parameter pack of specialised templates that hold argument data. Here's my desired outer syntax:
Function<
void /*Return type*/,
Arg<false, int> /*Required int parameter*/,
Arg<true, bool, true> /*Optional bool parameter that defaults to true*/
> func;
I would have liked to maintain the Function<ReturnType(args)> syntax but it appears you can only put typenames in parentheses and not classes. Here's my current code:
template<bool Optional, typename Type, Type Default>
class Arg;
template<typename Type, Type Default>
class Arg<false, Type, Default> {};
template<typename Type, Type Default>
class Arg<true, Type, Default> {};
Problem 1: I can't find a way to make the "Default" parameter non-required for the false specialisation. I've tried proxy classes with a default constructor, changing the third argument to a pointer and with specifying nullptr (which isn't really ideal syntactically), and a const reference to a type (which still requires three arguments from the user side) but nothing seems to allow two arguments to be accepted with Function<false, Type>.
Problem 2: I can't find the right syntax to get a parameter pack of mixed template argument types. I've tried (obviously invalid syntax)
template<typename RetType, Arg<bool, typename Type, Type>... args>
class Function{};
and even a double/nested template but I can't make this work either.
All of this indirection really steams from the fact that you can't have multiple parameter packs in a class template so I have to find creative ways to specify optional arguments, but I will take any solution I can get to somehow making this function at compile-time and not having to construct these functions dynamically.
I'm using C++20.
To make the third template argument optional when the first argument is false, you can use a default argument with a std::enable_if:
template <bool Optional, typename T,
T Default = std::enable_if_t<!Optional, T>{}>
class Arg;
This way, Arg<false, int> is equivalent to Arg<false, int, 0>, whereas Arg<true, int> is ill-formed.
You can use generic arguments:
template <typename R, typename... Args>
class Function {
static_assert(std::conjunction_v<is_arg_v<Args>...>);
};
Where is_arg can be something as simple as
template <typename T>
struct is_arg :std::false_type {};
template <bool Optional, typename T, T Default>
struct is_arg<Arg<Optional, T, Default>> :std::true_type {};
template <typename T>
inline constexpr bool is_arg_v = is_arg<T>::value;
I just asked this question: Can I get the Owning Object of a Member Function Template Parameter? and Yakk - Adam Nevraumont's answer had the code:
template<class T>
struct get_memfun_class;
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
using type=T;
};
These is clearly an initial declaration and then a specialization of struct get_memfun_class. But I find myself uncertain: Can specializations have a different number of template parameters?
For example, is something like this legal?
template<typename T>
void foo(const T&);
template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);
Are there no requirements that specializations must take the same number of parameters?
You seem to confuse the template parameters of the explicit specialization and the template arguments you use to specialize the template.
template<class T> // one argument
struct get_memfun_class; // get_memfun_class takes one template (type) argument
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
// ^^^^^^^^^^^^^^^^
// one type argument
using type=T;
}; // explicit specialization takes one template argument
Yes, there are three template parameters for the explicit specialization, but that doesn't mean that the explicit specialization takes three arguments. They are there to be deduced. You can form a single type using multiple type parameters, which is what is happening there. Also consider that you can fully specialize a template:
template <>
struct get_memfun_class<void>;
// ^^^^
// one type argument
Here it's the same thing. Yes, the explicit specialization takes no parameters, but that just means that there is none to be deduced and indeed you are explicitly writing a template parameter (void) and so the amount of template arguments of the specialization match those of the primary template.
Your example is invalid because you cannot partially specialize functions.
Are there no requirements that specializations must take the same number of parameters?
There is; and is satisfied in your example.
When you write
template<class T>
struct get_memfun_class;
you say that get_mumfun_class is a template struct with a single template typename argument; and when you write
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
using type=T;
};
you define a specialization that receive a single template typename argument in the form R(T::*)(Args...).
From the single type R(T::*)(Args...), you can deduce more that one template paramenters (R, T and the variadic Args..., in this example) but the type R(T::*)(Args...) (a method of a class that receive a variadic list of arguments) remain one.
For example, is something like this legal?
template<typename T>
void foo(const T&);
template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);
No, but (as written in comments) the second one isn't a class/struct partial specialization (where std::pair<K, V> remain a single type), that is legal; it's a template function partial specialization that is forbidden.
But you can full specialize a template function; so it's legal (by example)
template<>
void foo<std::pair<long, std::string>(const std::pair<long, std::string>&);
as is legal the full specialization for get_memfun_class (to make another example)
template<>
struct get_memfun_class<std::pair<long, std::string>> {
using type=long long;
};
I have such a template in C++
template<typename T, T* P> struct Ptr {};
so I can use it as such:
const int i = 0;
Ptr<int, &i> ptr;
or
Ptr<decltype(i), &i> ptr;
But I don't want to specify the type int or identity i twice, I want to use just
Ptr<&i> ptr;
and let the compiler figure out the int type part by itself.
How can I declare my template to do that ?
I've read this question but the answer is using macros, that's not nice:
template of template c++?
can I do this by just template without macros ? I'm using Visual C++ 2013.
UPDATE
c++17 introduced "P0127R2 Declaring non-type template parameters with auto", allowing to declare a non-type template parameter(s) with auto as a placeholder for the actual type:
template <auto P> struct Ptr {};
That is, P is a non-type template parameter. Its type can be inferred with decltype(P).
auto in a template parameter list is subject to well-known deduction and partial ordering rules. In your case, the type can be constrained to accept pointers only:
template <auto* P> struct Ptr {};
Note that the syntax utilizing auto is sufficient even for more detailed inspection, e.g.:
template <typename F>
struct FunctionBase;
template <typename R, typename... Args>
struct FunctionBase<R(*)(Args...)> {};
template <auto F>
struct Function : FunctionBase<decltype(F)> {};
It's also possible to use the inferred type as a contraint for other template parameters:
template <auto I, decltype(I)... Is>
struct List {};
Old answer
Since you are asking about a pure class template-based solution without the help of macro definitions then the answer is simple: as for now (Dec 2014, c++14) it is not possible.
This issue has been already identified by the WG21 C++ Standard Committee as a need and there are several proposals to let templates automatically infer the type of non-type template arguments.
The closest is N3601 Implicit template parameters:
Implicit template parameters
The purpose of this example is to eliminate the need for the redundant template<typename T, T t> idiom. This idiom is widely used, with over 100k hits on Google.
The goal is to be able to replace a template declaration like template<typename T, T t> struct C; with another declaration so that we can instantatiate the template like C<&X::f> instead of having to say C<decltype(&X::f), &X::f>.
The basic idea is to be able to say template<using typename T, T t> struct C {/* ... */}; to indicate that T should be deduced. To describe in more detail, we consider some extended examples of template classes and functions.
[...]
The key idea is that passing the type of the second template parameter is redundant information because it can be inferred using ordinary type deduction from the second type parameter. With that in mind, we propose that prefacing a template parameter with using indicates that it should not be passed explicitly as a template argument but instead will be deduced from subsequent non-type template arguments. This immediately allows us to improve the usability of describe_field as follows.
template<using typename T, T t> struct describe_field { /* ... */ };
/* ... */
cout << describe_field<&A::f>::name; // OK. T is void(A::*)(int)
cout << describe_field<&A::g>::arity; // OK. T is double(A::*)(size_t)
A similar proposal is the one included in N3405 Template Tidbits:
T for two
The motivating example is a putative reflection type trait giving properties of a class member.
struct A {
void f(int i);
double g(size_t s);
};
/* ... */
cout << describe<&A::f>::name; // Prints "f"
cout << describe<&A::g>::arity; // prints 1
The question is "what should the declaration of describe look like?" Since it takes a non-type template parameter, we need to specify the type of the parameter using the familiar (100k hits on Google) “template<class T, T t>” idiom
template<typename T, T t> struct describe;
[...]
Our key idea is that passing the type of the second template parameter is (nearly always) redundant information because it can be inferred using ordinary type deduction from the second type parameter. With that in mind, we propose allowing describe to be declared as follows.
template<typename T t> struct describe;
/* ... */
cout << describe<&A::f>::name; // OK. T is void(A::*)(int)
cout << describe<&A::g>::arity; // OK. T is double(A::*)(size_t)
The current status of both proposals can be tracked under EWG issue 9.
There are some other discussions proposing alternative syntax with auto:
template <auto T> struct describe;
I have such a template in C++
template<typename T, T* P> struct Ptr {};
so I can use it as such:
const int i = 0;
Ptr<int, &i> ptr;
or
Ptr<decltype(i), &i> ptr;
But I don't want to specify the type int or identity i twice, I want to use just
Ptr<&i> ptr;
and let the compiler figure out the int type part by itself.
How can I declare my template to do that ?
I've read this question but the answer is using macros, that's not nice:
template of template c++?
can I do this by just template without macros ? I'm using Visual C++ 2013.
UPDATE
c++17 introduced "P0127R2 Declaring non-type template parameters with auto", allowing to declare a non-type template parameter(s) with auto as a placeholder for the actual type:
template <auto P> struct Ptr {};
That is, P is a non-type template parameter. Its type can be inferred with decltype(P).
auto in a template parameter list is subject to well-known deduction and partial ordering rules. In your case, the type can be constrained to accept pointers only:
template <auto* P> struct Ptr {};
Note that the syntax utilizing auto is sufficient even for more detailed inspection, e.g.:
template <typename F>
struct FunctionBase;
template <typename R, typename... Args>
struct FunctionBase<R(*)(Args...)> {};
template <auto F>
struct Function : FunctionBase<decltype(F)> {};
It's also possible to use the inferred type as a contraint for other template parameters:
template <auto I, decltype(I)... Is>
struct List {};
Old answer
Since you are asking about a pure class template-based solution without the help of macro definitions then the answer is simple: as for now (Dec 2014, c++14) it is not possible.
This issue has been already identified by the WG21 C++ Standard Committee as a need and there are several proposals to let templates automatically infer the type of non-type template arguments.
The closest is N3601 Implicit template parameters:
Implicit template parameters
The purpose of this example is to eliminate the need for the redundant template<typename T, T t> idiom. This idiom is widely used, with over 100k hits on Google.
The goal is to be able to replace a template declaration like template<typename T, T t> struct C; with another declaration so that we can instantatiate the template like C<&X::f> instead of having to say C<decltype(&X::f), &X::f>.
The basic idea is to be able to say template<using typename T, T t> struct C {/* ... */}; to indicate that T should be deduced. To describe in more detail, we consider some extended examples of template classes and functions.
[...]
The key idea is that passing the type of the second template parameter is redundant information because it can be inferred using ordinary type deduction from the second type parameter. With that in mind, we propose that prefacing a template parameter with using indicates that it should not be passed explicitly as a template argument but instead will be deduced from subsequent non-type template arguments. This immediately allows us to improve the usability of describe_field as follows.
template<using typename T, T t> struct describe_field { /* ... */ };
/* ... */
cout << describe_field<&A::f>::name; // OK. T is void(A::*)(int)
cout << describe_field<&A::g>::arity; // OK. T is double(A::*)(size_t)
A similar proposal is the one included in N3405 Template Tidbits:
T for two
The motivating example is a putative reflection type trait giving properties of a class member.
struct A {
void f(int i);
double g(size_t s);
};
/* ... */
cout << describe<&A::f>::name; // Prints "f"
cout << describe<&A::g>::arity; // prints 1
The question is "what should the declaration of describe look like?" Since it takes a non-type template parameter, we need to specify the type of the parameter using the familiar (100k hits on Google) “template<class T, T t>” idiom
template<typename T, T t> struct describe;
[...]
Our key idea is that passing the type of the second template parameter is (nearly always) redundant information because it can be inferred using ordinary type deduction from the second type parameter. With that in mind, we propose allowing describe to be declared as follows.
template<typename T t> struct describe;
/* ... */
cout << describe<&A::f>::name; // OK. T is void(A::*)(int)
cout << describe<&A::g>::arity; // OK. T is double(A::*)(size_t)
The current status of both proposals can be tracked under EWG issue 9.
There are some other discussions proposing alternative syntax with auto:
template <auto T> struct describe;