Template array length as argument - c++

I am trying to learn more about templates in C++. I would like to be able to call a function where I pass it a type and the length as an argument. Is this possible?
template <class T>
void alloc_arr (int l) {
std::allocator<T[l]> a;
}
alloc_arr<int[]>(64);
It doesn't work because the instantiated type must be fixed at compile time (T[l] is not fixed).
Is there some other way to do this which doesn't require the length to be specified in the type (<T[64]>)?

Is there some other way to do this which doesn't require the length to be specified in the type ()?
In some way, you need to pass it as template parameter
You can pass it explicitly, as suggested by Lourens Dijkstra
template <typename T, std::size_t Dim>
void alloc_arr ()
{
std::allocator<T[Dim]> a;
// ...
}
or, if you can use at least C++11, also you can deduce it from the type of an argument; by example,
template <typename T, std::size_t Dim>
void alloc_arr (std::integral_constant<std::size_t, Dim> const &)
{
std::allocator<T[Dim]> a;
// ...
}
or also
template <typename T, typename U>
void alloc_arr (U const &)
{
std::allocator<T[U::value]> a;
// ...
}
calling alloc_arr with a std::integral_constant<std::size_t, 5u>{}, by example.

You could pass the size as a template parameter:
template <class T, size_t size>
void alloc_arr() { ... }
This is the only way. A couple of days ago I found out that passing a constexpr lambda as a regular parameter is considered ill-formed: Trying to pass a constexpr lambda and use it to explicitly specify returning type
Also, note that type T should be int; not int[].
So, calling alloc_arr:
alloc_arr<int, 64>();

Related

Is there a way to use variable template as a parameter?

I want to declare a function, which will take as a parameter a variable (let's say, int), which should be parametrized by a class. Speaking in terms of lambda calculus, I want my parameter to have a kind * -> int.
Example of a function I want to be able to write (Spec is the variable):
template <??? Specification, typename T>
auto make_array() {
return std::array<T, Specification<T>>;
}
Since C++14 we have variable templates, so we can do something like this:
template <typename T>
constexpr int digits = std::numeric_limits<T>::digits;
The problem is, how do I pass that into a function? In the notes section of cppreference it is stated that
Variable templates cannot be used as template template arguments.
But does that mean that there is actually no way to pass parametrized variable as a function parameter? What you can do is, for example, create a class which has a static field denoting value, but an obvious drawback is that the users of my function must derive from that class.
I believe there might be some workaround using SFINAE, but I lack skills in that area.
Unless you insist on using a variable template, you can use a type trait:
template <typename T> struct Specification;
you can specialize it for example for int:
template <>
struct Specification<int> {
static constexpr size_t value = 42;
};
and as you want to have different Specifications, pass it as template template parameter:
template <template<class> class S, typename T>
auto make_array() {
return std::array<T, S<T>::value>{};
}
Complete example:
#include <array>
#include <cstddef>
template <template<class> class S, typename T>
auto make_array() {
return std::array<T, S<T>::value>{};
}
template <typename T> struct Specification;
template <>
struct Specification<int> {
static constexpr size_t value = 42;
};
int main(){
auto x = make_array<Specification,int>();
}
Note that I was rather verbose for the sake of clarity. You can save a bit of typing by using std::integral_constant, eg:
template <>
struct Specification<double> : std::integral_constant<size_t,3> {};
As an follow-up on idclev's answer, you can avoid the need to explicitly specialise for the different types for individual "specifications" just by inheriting from e.g. integral_constant. For example, your desired usage was something like
template <template <typename T> int Specification, typename T>
auto make_array() {
return std::array<T, Specification<T>>;
}
template <typename T>
constexpr int digits = std::numeric_limits<T>::digits;
// ...
auto foo = make_array<digits, double>();
However, as you have noted, this is impossible: you cannot pass variable templates as template-template parameters. However, by turning digits into a structure directly you can do this:
template <template <typename T> class Specification, typename T>
auto make_array() {
// we no longer have the guarantee of the type here, unfortunately
// but you can use a static_assert to improve error messages
// (also using `std::size_t` here for correctness)
static_assert(
std::is_convertible<decltype(Specification<T>::value), std::size_t>::value,
"value must be convertible to size_t");
return std::array<T, Specification<T>::value>;
}
// use a type rather than a variable template
// we just inherit from integral constant to save on some typing
// (though you could do this explicitly as well)
template <typename T>
struct digits : std::integral_constant<int, std::numeric_limits<T>::digits> {};
// ...
// same call!
auto foo = make_array<digits, double>();

C++17 Partial Deduction Guide

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
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.
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;
};

template template function definition

I have a template class called Array
template<typename T, int dimension>
class Array<typename T, int dimension>{
//definition of the class
}
I want to write a non-member function cast such that I can cast Array into different type. For example
Array<int, 2> a;
Array<float, 2> b = cast<float>(a);
How should I write this function? I am more interested in how to declare it instead of how to implement the detailed casting. I have tried
template<template<typename T, int dimension> class Array, typename New_T, int dimension>
Array<typename New_T, int dimension> cast(Array<typename T, int dimension> a){
// detailed implementation of casting, which I do not care for this question.
}
but it cannot pass the compilation.
You don't need template template parameters at all here. Simple typename and int parameters will do:
template <typename T, int dimension>
class Array
{
// ...
};
template <typename NewT, typename T, int dimension>
Array<NewT, dimension> cast(const Array<T, dimension>& a)
{
// ...
}
Live Demo
You only need template template parameters when you want to accept different types of templates. For instance, if you wanted cast to be able to accept an Array or a std::array, you could use a template template parameter:
template<typename NewT, typename T, auto dimension, template<typename, auto> typename ArrayT>
ArrayT<NewT, dimension> cast(const ArrayT<T, dimension>& a)
{
// ...
}
Live Demo
Note in this case I also changed the type of dimension to auto since std::array uses a size_t for its dimension while your Array uses int.
How should I write this function? I am more interested in how to define it instead of how to implement the detailed casting.
I suppose something like
template <typename ToT, typename FromT, int Dim>
Array<ToT, Dim> cast (Array<FromT, Dim> const & inA)
{
// ...
}
It's useful place ToT (to-type) in first position so you can explicit it and let FromT and Dim deduced from the inA value.
--- EDIT ---
The OP asks
Any insight why I have to put it [ToT] in the first position?
You don't necessarily have to put ToT in first position. But this simplify your life.
The point is that FromT and Dim are deducible from the inA argument; ToT isn't deducible from arguments so you have to explicit it.
But if you want to explicit a template parameter, you necessarily have to explicit the preceding parameters. So if you put ToT in last position, you have to call cast() explicating all template parameters
cast<int, 2, float>(a);
If you place ToT in first position, you have to explicit only it and leave the compiler deduce FromT and Dim from the argument
cast<float>(a);

Function type not a valid type for a template non-type parameter?

OpenGL defines C functions to manage resources. I wrote a simple wrapper to handle them in the RAII way. Function pairs are like unsigned glCreateProgram() and void glDeleteProgram(unsigned program). However, there're function pairs which work on arrays of resources like void glGenBuffers(size_t n, unsigned* buffers) and void glDeleteBuffers(size_t n, const unsigned* buffers);. For the former I wrote a simple class to do the job, and for the latter I wrote another class which handles arrays. However, I noticed that at times I just use only one buffer or texture, where I don't have to incur the expense of a vector, I thought I'll specialize the class destructor if the release function takes a size parameterr in the beginning BUT...
template <typename T_res,
typename T_release_func,
T_release_func func>
struct GL_resource
{
GL_resource(T_res name_) : name{name_}
{
}
~GL_resource()
{
func(name);
}
private:
T_res name;
};
template <typename T_res, typename FT, FT func, typename RT, typename DT>
struct GL_resource<T_res, RT (size_t, DT*), func>
{
~GL_resource()
{
func(1, name);
}
};
for the above SSCCE g++ barks:
error: 'RT(unsigned int, DT*)' is not a valid type for a template non-type parameter struct GL_resource
I then wrote a dummy function void release(size_t, int*) {} and rewrote the specilization as
template <typename T_res, typename FT, FT func>
struct GL_resource<T_res, decltype(release), release>
{
~GL_resource()
{
func(1, name);
}
};
This time I got:
error: 'void(unsigned int, int*)' is not a valid type for a template non-type parameter struct GL_resource.
Can someone explain why?
Functions aren't values, so they can't be non-type template parameters; but pointers to functions can be:
template <typename T_res, typename RT, typename DT, RT (*func) (size_t, DT*)>
struct GL_resource<T_res, RT (*)(size_t, DT*), func>
{
~GL_resource()
{
func(1, name);
}
};
Note that functions are subject to pointer decay even when used as non-type template parameters, so FT will always be a pointer-to-function type, not a function type.

Why can't C++ infer the template type?

Why can't the compiler figure out these template parameters? Is there a way to make it do so?
(I'm using Visual Studio 2010.)
template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }
void myfunc(void *) { }
int main() { call(myfunc); }
T appears nowhere in the parameter list so T cannot be deduced from the function arguments. All types to be deduced must appear in deduced contexts in the parameter list. For example,
template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
f(TParameter());
}
Template parameter deduction for function templates only works based on function arguments, nothing else. The function definition is never looked at for the purpose of determining the template parameters, so your parameter T cannot possibly be deduced.
You could remedy your situation by incorporating the type into the function signature: Since you expect the outer function to be called with a function itself, make that explicit:
template <typename T> void foo(void(*f)(T))
{
T x;
f(x);
// ...
}
Combine function overloading with functors, and it becomes impossible in the general case to determine what arguments can be passed to a callable entity.
Consider, for example
struct FunctorExample {
void operator()(int x) {...}
std::string operator()(const std::string& ) {...}
};
If there were some way to coax the compiler to pattern match on arguments, it would have to have undefined or error behavior when applied to FunctorExample.
Instead, the trend seems to be that when you want to template metaprogram with functors, you specify the functor and argument list. Examples (off the top of my head) being boost::result_of and boost::fusion.
Edit: That said, if you're willing to restrict your attention somewhat, and you can use some C++11 syntax (decltype), you can arrange to introspect a bit more:
// Support functors with a very simple operator():
template <typename T> struct argument :
public argument<decltype(&T::operator())> {};
// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
{typedef A type;};
// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};
// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};
// Now for call:
template <typename FuncType>
void call(FuncType func) {
typedef typename argument<FuncType>::type Arg;
func(Arg());
}
// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}
int main() {
call(myfunc);
call(FunctorInt());
}
Variadic templates could be used to expand this stuff to support more than one argument.