Home > Software design >  C function with a viariable number of arguments of a certain type
C function with a viariable number of arguments of a certain type

Time:04-11

I just learnt about variatics in C , implemented it but I wanted to know if it could do this:

If i want a function with 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:

  • Is there a way to force a certain type with variatics (something like this)?
    template <float... Fs>
    f(Fs... args); // unlimited number of arguments but only float
  • If not, is there a way to check it at compile time? static_assert(std::is_same<A,B>) is fine in most cases but doesn't work for templated classes, like (for my use case):
    template <typename T, uint16_t dimension>
    class Vector
    {
        template <typename... Ts>
        Vector(Ts... args)
        {
            static_assert(sizeof...(args) == dimension);
            static_assert(std::is_same_v<Ts..., T>()); //doesn't work because Ts will
                                                       //develop into a lot of template 
                                                       //arguments. Just putting Ts doesn't
                                                       //work either.
        }
    }

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.

Thanks for your answers!

CodePudding user response:

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 )
    {
    }
};
  • Related