c++ template parameter type inference - c++

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;

Related

How can I create deduction guides for template aliases in C++20?

Suppose I have a class/struct template together with an explicit deduction guide for its constructor. Let this class have two template parameters of which one can get deduced by the deduction guide, for the other it can not.
template <int Q, typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
using alias = T;
template <typename T>
struct alias2 { using type = T; };
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, alias<F>>; // deduction guide, but cannot deduce Q yet
template <typename T>
using Bar = Foo<1, T>; // create alias that fixes Q
/* This should generate a deduction guide for Bar<T> by first
"copying" Foo's deduction guide, deducing from Foo<Q, alias<F>>
and Foo<1, T> that Q=1 and T=alias<F>=F, thus generating
<template F>
Bar(F&&) -> Bar<1, F>;
if this was correct syntax. */
int main() {
Bar f{ 5 };
}
If I now create an alias that will explicitly specify the formerly undeducable parameter, as far as I understand, the implicitly-generated deduction guide of this alias should be able to fully deduce both template arguments (by the rules of standard template argument deduction), even if one type is undeduced in the defining class template.
But what can I do in the scenario where I do not use alias, but alias2, i.e. change the deduction guide to
template <int Q, typename F>
Foo(F&& f) -> Foo<Q, typename alias2<F>::type>;
According to the documentation, this would now introduce a non-deduced context (as the template parameter appears left to a scope operator ::), so the template argument deduction for T=F should fail (which apparently does).
Question 1: If this theory is correct, is there something I can do about it? Suppose I do not want to use a trivial identity alias, but a more complex type transformation that will ultimatively have the shape of a typename transformation<Input>::result in the deduction guide.
Question 2: Even now, my theory fails when I remove Q entirely, as the following code will be accepted (by GCC-10/11):
template <typename T>
struct Foo {
template <typename F>
Foo(F&&) { }
};
template <typename T>
struct alias2 { using type = T; };
template <typename F>
Foo(F&& f) -> Foo<typename alias2<F>::type>;
template <typename T>
using Bar = Foo<T>;
template <typename T>
void some(typename alias2<T>::type) { }
int main() {
Bar f{ 5 };
}
Why is the compiler able to deduce T from F even if this is a non-deduced context?
To do what you want, C++ would have to be able to invert a Turing-complete subprogram.
Turing-complete programs are not only not-invertible, it isn't possible to determine if a given Turing-complete program is invertible or not. You can define sublanguages where they are all invertible, but those sublanguages lack Turing-complete power.
Deducing the Bar alias argument:
template <typename T>
using Bar = Foo<1, T>;
requires inverting the 2nd template argument alias<F> to find F. When alias is a trivial template alias, this is possible, permitted, and required by the C++ standard.
When alias2 evaluates is to a foo<F>::type, such a construct is capable of turing-complete computation. Rather than have compilers try to invert such a computation, the C++ standard uniformly says "don't try". It uses "dependent type" usually to block such an inversion attempt.
In your second case, Bar is a trivial alias of Foo. Foo has a deduction guide. That deduction guide tells how to get from F to T, so the compiler doesn't have to invert any potentially Turing-complete programs in order to determine T.
The C++ language has a bunch of wording to permit template aliases that are just renaming of parameters or the like to act as if they were the original type. Originally even a toy alias would block a bunch of this kind of deduction; but this was found to be a bad plan. So they added text to the standard to describe what kind of template aliases where "trivial" like that, and modified the wording of deduction rules so that they would be treated as transparent.
In order to invert an arbitrary Turing-complete program (in fact, almost any structurally non-trivial type transformation) during type deduction, you must explicitly give the inversion.
Once you have accepted that, it becomes battle with syntax, not a conceptual one.
I'm unaware of the current status of user-defined template deduction guides of alias templates. Last I heard it wasn't supported, but I haven't checked recently.

Check if class is a template specialization

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!

Partial template specialization type collapsing rules

Sorry for the lack of a better title.
While trying to implement my own version of std::move and understanding how easy it was, I'm still confused by how C++ treats partial template specializations. I know how they work, but there's a sort of rule that I found weird and I would like to know the reasoning behind it.
template <typename T>
struct BaseType {
using Type = T;
};
template <typename T>
struct BaseType<T *> {
using Type = T;
};
template <typename T>
struct BaseType<T &> {
using Type = T;
};
using int_ptr = int *;
using int_ref = int &;
// A and B are now both of type int
BaseType<int_ptr>::Type A = 5;
BaseType<int_ref>::Type B = 5;
If there wasn't no partial specializations of RemoveReference, T would always be T: if I gave a int & it would still be a int & throughout the whole template.
However, the partial specialized templates seem to collapse references and pointers: if I gave a int & or a int * and if those types match with the ones from the specialized template, T would just be int.
This feature is extremely awesome and useful, however I'm curious and I would like to know the official reasoning / rules behind this not so obvious quirk.
If your template pattern matches T& to int&, then T& is int&, which implies T is int.
The type T in the specialization only related to the T in the primary template by the fact it was used to pattern match the first argument.
It may confuse you less to replace T with X or U in the specializations. Reusing variable names can be confusing.
template <typename T>
struct RemoveReference {
using Type = T;
};
template <typename X>
struct RemoveReference<X &> {
using Type = X;
};
and X& matches T. If X& is T, and T ia int&, then X is int.
Why does the standard say this?
Suppose we look af a different template specialization:
template<class T>
struct Bob;
template<class E, class A>
struct Bob<std::vector<E,A>>{
// what should E and A be here?
};
Partial specializations act a lot like function templates: so much so, in fact, that overloading function templates is often mistaken for partial specialization of them (which is not allowed). Given
template<class T>
void value_assign(T *t) { *t=T(); }
then obviously T must be the version of the argument type without the (outermost) pointer status, because we need that type to compute the value to assign through the pointer. We of course don't typically write value_assign<int>(&i); to call a function of this type, because the arguments can be deduced.
In this case:
template<class T,class U>
void accept_pair(std::pair<T,U>);
note that the number of template parameters is greater than the number of types "supplied" as input (that is, than the number of parameter types used for deduction): complicated types can provide "more than one type's worth" of information.
All of this looks very different from class templates, where the types must be given explicitly (only sometimes true as of C++17) and they are used verbatim in the template (as you said).
But consider the partial specializations again:
template<class>
struct A; // undefined
template<class T>
struct A<T*> { /* ... */ }; // #1
template<class T,class U>
struct A<std::pair<T,U>> { /* ... */ }; // #2
These are completely isomorphic to the (unrelated) function templates value_assign and accept_pair respectively. We do have to write, for example, A<int*> to use #1; but this is simply analogous to calling value_assign(&i): in particular, the template arguments are still deduced, only this time from the explicitly-specified type int* rather than from the type of the expression &i. (Because even supplying explicit template arguments requires deduction, a partial specialization must support deducing its template arguments.)
#2 again illustrates the idea that the number of types is not conserved in this process: this should help break the false impression that "the template parameter" should continue to refer to "the type supplied". As such, partial specializations do not merely claim a (generally unbounded) set of template arguments: they interpret them.
Yet another similarity: the choice among multiple partial specializations of the same class template is exactly the same as that for discarding less-specific function templates when they are overloaded. (However, since overload resolution does not occur in the partial specialization case, this process must get rid of all but one candidate there.)

how to declare properly the template taking function type as a parameter (like a std::function)

I found out that its not trivial to have a neat syntax like in:
std::function<int(float, bool)>
If I declare the function as:
template <class RetType, class... Args>
class function {};
It would be an ordinary syntax to define function's templated types:
function<int,float,bool> f;
But it works with strange trick with partial template specialization
template <class> class function; // #1
template <class RV, class... Args>
class function<RV(Args...)> {} // #2
Why is that?
Why I need to give the template an empty general form with empty type parameter (#1) or otherwise it just won't compile
This is just the way the language was designed. Primary templates can't do complex decomposition of types like that; you need to use partial specialization.
If I understand correctly, you would like to just write the second version without having to supply the primary template. But think about how the template arguments map to the template parameters:
template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}
function<int(float,bool)>; //1
function<int, float, bool>; //2
Option 1 is what you want to write, but note that you pass a single function type to a template where the parameters are a two type parameters and a type parameter pack. In other words, writing this without a primary template means that your template arguments wouldn't necessarily match the template parameters. Option 2 matches the template parameters, but it doesn't match the specialization.
This makes even less sense if you have more than one specialization:
template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}
template <class T, class RV, class Arg1, class... Args>
class function<RV (T::*) (Arg1, Args...)> {}
You could maybe think up some rules to infer the primary template from the specializations, but that seems pretty awful to me.
You have to keep in mind that int (float, bool) is a type. More precisely, it's the type "function which takes two parameters of type float and bool, and returns int."
Since it's a type, it's obvious the template must have one type parameter in the place where you want to use the syntax int (float, bool).
At the same time, having just the function type is unwieldy. Sure, you could do it easily. For example, if all you need to do is some kind of a forwarder:
template <class T>
struct CallForwarder
{
std::function<T> forward(std::function<T> f)
{
std::cout << "Forwarding!\n";
return f;
}
};
However, as soon as you want access to the "components" of the function type, you need a way to introduce identifiers for them. The most natural way to do so is the partial specialisation for function types, just as you did in your question (and just as std::function does).
You can actually do this:
template <typename T>
class X { };
X<int(char)> x;
And inside the definition of X you could create a std::function<T> as you would create a std::function<int(char)>. The problem here is that you cannot (at least easily) access the return type and the type of the parameters of the argument (int and char here).
Using the "trick", you can access these without problem - It "simply" makes your code cleaner.
"Why I need to give the template an empty general form with empty type parameter"
Because, you want explicit type differentiation among the "return type" and the "argument types", with the similar lucidness of syntactic sugar. In C++, no such syntax is available for the first hand version of the template class. You must have to specialize it, to be able to distinguish it.
After reading your Q, I looked at the <functional> header file. Even std::function does the same trick:
// <functional> (header file taken from g++ Ubuntu)
template<typename _Signature>
class function;
// ...
/**
* #brief Primary class template for std::function.
* #ingroup functors
*
* Polymorphic function wrapper.
*/
template<typename _Res, typename... _ArgTypes>
class function<_Res(_ArgTypes...)>
As you see in their comments, they treat the specialized version as the "Primary" class. Hence this trick is coming from the standard header itself!

Deduce return and parameter types of function pointer passed as non-type template argument [duplicate]

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;