Mmjay
Mmjay

Reputation: 3

Optional function parameter based value of template parameter

So I understand I could probably solve this problem by simply using a parameter pack, but that solution seems a little ugly to me. What I want to do is something like the following:

template<bool test>
void Foo(int x, int y, int z, /*if test is set to true*/ int w)
{
   if constexpr(test)
   {
     //use w for something.
   }
}

So basically use the template parameter to say whether the last parameter is required or not. If test is false and an argument is passed in for w then there should be a compilation error saying too many arguments were provided. Any ideas what is available to me to achieve something like this elegantly?

Upvotes: 0

Views: 82

Answers (2)

Woodford
Woodford

Reputation: 4449

I think templates are the wrong tool for the job here. Instead you can use std::optional to do what you're looking for:

#include <optional>

void Foo(int x, int y, int z, std::optional<int> w=std::nullopt) {
    if (w) {
      // use (*w) for something.
    }
}

int main() {
    Foo(1, 2, 3);
    Foo(1, 2, 3, 100);
}

Upvotes: 0

lorro
lorro

Reputation: 10880

You might decouple interface from implementation, use overloads and enable_if:

namespace detail
{
    struct Empty {};

    template<typename T>
    void FooImpl(int x,int y, int z, T w)
    {
        constexpr test = std::is_same_v<T, Empty>;
        if constexpr(test)
        {
            //use w for something
        }
    }
}

template<bool test>
std::enable_if_t<test> void Foo(int x, int y, int z, int w)
{
   detail::FooImpl(x, y, z, w);
}

template<bool test>
std::enable_if_t<!test> void Foo(int x, int y, int z)
{
   detail::FooImpl(x, y, z, detail::Empty{});
}

Note that in the generic case, you’d likely use std::forward<> on the interface and perhaps document (using a static_assert()) that the type of w is Empty or int.

Upvotes: 1

Related Questions