EloiGG
EloiGG

Reputation: 43

C++ function with a viariable number of arguments of a certain type

I just learned about variadic templates in C++. I implemented it, but I want to know, can it do the following?

If I want a function with a variable number of arguments, I could do that:

template <typename... Ts>
f(Ts... args);

But I lose type safety (I don't know the type of the arguments).

What if I know my function needs only float as arguments? I want to make sure at compile-time that every argument is the type I want.

So these are my questions:

Ps: Yes I could use std::vector or std::array as arguments, but that's not really the point. Plus, I want to keep the beautiful Vector(2.0, 1.0, 0.0) syntax, not using curly braces.

Upvotes: 4

Views: 186

Answers (3)

Jarod42
Jarod42

Reputation: 217075

In the case of fixed vector as in your case, there is an alternative with std::index sequence:

// helper for folding
template <typename T, std::size_t /*ignored*/>
using always_t = T;

template <typename T, typename Seq>
class VectorImpl;

template <typename T, std::size_t... Is>
class VectorImpl<T, std::index_sequence<Is...>>
{
public:
    VectorImpl(always_t<T, Is>... args); // equivalent to VectorImpl(T arg1, T arg2, ..)
    // ...
};

template <typename T, std::size_t N>
using Vector = VectorImpl<T, std::make_index_sequence<N>>;

Upvotes: 0

Let&#39;s do it
Let&#39;s do it

Reputation: 21

template <typename T, uint16_t dimension>
class MyVector
{
  public:
    template <typename... Ts>
    MyVector(Ts... args)
    {
        static_assert(sizeof...(args) == dimension);
        static_assert((std::is_same<T,Ts>::value && ...) );
    }
};

Can also use the unary right fold expression as provided in C++17 https://en.cppreference.com/w/cpp/language/fold

This essentially does

std::is_same<T,Ts_1>::value && ( std::is_same<T,Ts_2>::value && ... std::is_same<T,Ts_n>::value ) ...)

And works also when the parameter pack Ts is empty. Quote from the reference link:

" Logical AND (&&). The value for the empty pack is true"

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 310910

If the compiler supports C++ 20 then you can write for example

#include <type_traits>

template <typename T, uint16_t dimension>
class Vector
{
public:
    template <typename... Ts>
    Vector( Ts &&... args ) requires ( sizeof...( args ) == dimension ) && std::conjunction_v<std::is_same<T, std::decay_t<Ts>>...>
    {
    }
};

//...

Vector<float, 5> v( 1.1f, 2.2f, 3.3f, 4.4f, 5.5f );

Or as @HolyBlackCat wrote in a comment you may also write

template <typename T, uint16_t dimension>
class Vector
{
public:
    template <typename... Ts>
    Vector( std::same_as<T> auto ...args ) requires( sizeof...( args ) == dimension )
    {
    }
};

Upvotes: 1

Related Questions