10

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.

Community
  • 1
  • 1
WalkingCat
  • 263
  • 3
  • 10
  • Maybe if you could explain what is it exacly you are tring to achive? – Ravid Goldenberg Dec 09 '14 at 06:22
  • @petric: it seemed clear to me: the goal is to support `Ptr<&i> ptr;` and make the `int` type completely implicit rather than having to type it out. – John Zwinck Dec 09 '14 at 06:23
  • 2
    I guess it's not possible; You at least need to specify `int` when declaring `Ptr ptr;`, then you want to give your object a parameter, so that you need to specify it again: `Ptr ptr;` or something like `std::shared_ptr`: `Ptr ptr(&i);` – Marson Mao Dec 09 '14 at 06:24
  • @JohnZwinck if he would show the way he uses this type inside the struct it is possible to find a way to omit the T or the T* and get his way... – Ravid Goldenberg Dec 09 '14 at 06:27
  • 2
    @JohnZwinck I think petric was more asking what OP's goal is, ie *why* does he want to be able to do this. The problem in question seems like a strange one to want to solve. – Red Alert Dec 09 '14 at 06:27
  • @petric My goal is kinda similiar to the question I linked in the Q, the Ptr struct is used to access (get/set) some variable in a generic manner. – WalkingCat Dec 09 '14 at 06:36
  • oh crap I just noticed I linked to the wrong SO questing in the Q, the one I read was actually this, will edit the Q also. http://stackoverflow.com/questions/6569716/template-of-template-c – WalkingCat Dec 09 '14 at 06:40
  • 1
    @petric more specifically, the Ptr struct can have members like `T get() { return *P; }` and `set(T value) { *P = value; }` etc. – WalkingCat Dec 09 '14 at 07:14
  • 2
    This is exactly [N3601 Implicit template parameter](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3601.html), which is not yet supported – Piotr Skotnicki Dec 09 '14 at 07:28
  • @PiotrS. oh YES you are right! glad to know someone in the commitee is at least thinking about it. But it looks like I can't mark your comment as the answer. :-( – WalkingCat Dec 09 '14 at 07:37
  • You can use an ugly macro until N3601 is accepted. `#define PTR(t) Ptr` or something. – n. m. could be an AI Dec 09 '14 at 07:54
  • Possible duplicate of [What is the template idiom?](http://stackoverflow.com/questions/15983802/what-is-the-templatetypename-t-t-t-idiom) – Jonathan Mee Aug 05 '16 at 15:14

1 Answers1

13

UPDATE

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, ) 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;
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160