17

I am trying to write a deduction guide, that only detects one of many typename's from given constructor argument and requires user to enter int size manually

template <int size, typename T>
struct Board
{
            array<array<T, size>, size> values;

            explicit Board(const vector<T>& raw_values){

            }
};
template <int size, typename T> Board(const vector<T>&) -> Board<int size, T>;

The idea above is that user should still be forced to enter "int size" argument of template, but "typename T" should be deduced from the argument of constructor, is this possible?

After correct specification, this is how method should be called

auto b = Board<3>(initialStateVector);

Currently, it requires to me to enter like this;

auto b = Board<3, int>(initialStateVector);

So basically, I want "int" above to be deduced from given initialStateVector, which has type

const vector<int>& raw_values
max66
  • 65,235
  • 10
  • 71
  • 111
Eren
  • 316
  • 1
  • 9
  • 1
    `vector::size()` can only be known at runtime. You can't convert a vector to an `std::array` without knowing the size before hand. – David G May 28 '19 at 23:14
  • @0x499602D2 Thanks for answer, I know size of vector, it is 3, what i am trying to do here is not really about vectors though, Im trying to eliminate the need to specify int in Board<3, int>. – Eren May 28 '19 at 23:56
  • Does `Board<3>(initialStateVector)` give you a compile error? If so, what is it? –  May 29 '19 at 00:09
  • @Chipster It gives me a compile error at template Board(const vector&) -> Board; saying "typeid cannot have name" – Eren May 29 '19 at 00:14
  • That's weird. There's no `typeid()` in the code you posted. Maybe the error is another part of the code that you didn't post? –  May 29 '19 at 00:19
  • @Chipster code compiles and runs correctly when i remove that particular line – Eren May 29 '19 at 00:21
  • Hmm. That kind of makes sense.That line looks kind of broken. For one thing, you probably mean something like `Board::Board()` instead of just `Board()`. Why do you need that line? Is there a chance you can just remove it? It's not clear to me what benefit it is to you right now, since there is no implementation attached to it, and you implement the function in the struct declaration itself already anyway. –  May 29 '19 at 00:25
  • @Chipster I was trying to write a deduction guide for struct that only takes int size as template and deduces typename T from constructor's argument. Syntax itself is wrong and i was curious if there is a way to achieve what i wanted to do, it seems to be not possible – Eren May 29 '19 at 00:28
  • Can it not deduce it without the line? It looks like it should be able to. –  May 29 '19 at 00:30
  • @Chipster It gives "too few arguments for template" error without that line – Eren May 29 '19 at 00:37
  • Hmm. I must just be wrong then. I'll have to research why. –  May 29 '19 at 00:38

2 Answers2

10

The idea above is that user should still be forced to enter "int size" argument of template, but "typename T" should be deduced from the argument of constructor, is this possible?

According a note (and following examples) in this cppreference page

Class template argument deduction is only performed if no template argument list is present. If a template argument list is specified, deduction does not take place.

no, this isn't possible (not in C++17; we can hope in future versions of the standard).

If you want explicit the size and let deduce the type, the best I can imagine is pass through a good-old make_something function.

I mean something as follows (using std::size_t for the size, as in std::array and almost all STL)

template <std::size_t S, typename T>
Board<S, T> make_Board (std::vector<T> const & v)
 { return {v}; }

// ...

auto b = make_Board<3>(initialStateVector);

that should works also in C++11.

max66
  • 65,235
  • 10
  • 71
  • 111
  • Thank you very much sir, It is interesting that it can partially detect template's and take explicit size value in methods, but not on structs. Hopefully partial deduction guide's get added at some point in future to eliminate the need for make_x functiond – Eren May 29 '19 at 00:22
  • 1
    "*we can hope in future versions of the standard*" I wouldn't hold my breath; it was proposed and rejected for C++20. – Rakete1111 May 29 '19 at 19:13
  • 3
    @Rakete1111 I'm very interested to read more about this. Got any pointers? – Fabio A. Oct 17 '19 at 19:46
1

I came up with a workaround using a size hint object

template<int size>
struct SizeHint {};

Your class would take this as an additional constructor argument:

Board(SizeHint<size>, const std::vector<T>& raw_values)

You call the constructor like this:

auto b = Board(SizeHint<2>{}, v);

Bonus

This approach also works for type hints (my original motivation how I found this thread):

template<typename T>
struct TypeHint{};

template<typename Result, typename T>
struct S {
    S(TypeHint<Result>, T arg) : t{arg}{}
    Result r() {return t;}
    T t;
};

#include <iostream>
int main() {
    S s{TypeHint<int>{}, 5.7};
    std::cout << s.r() << std::endl;
}

This can also be used in combination with variadic templates:

template<typename Result, typename... Args>
struct S {
    S(TypeHint<Result>, Args... args) : t{args...}{}
    std::tuple<Args...> t;
};
darkdragon
  • 392
  • 5
  • 13