How can I prevent user from specifying a function template parameter, forcing it to be deduced?

What about making fancy_cast a variable template?

template <typename A>
struct fancy_cast_t {
    template <typename B>
    A operator()(B x) const { return x; }
};

template <typename A>
constexpr fancy_cast_t<A> fancy_cast {};

fancy_cast<int>(1.5);  // works
fancy_cast<int, int>(1.5);  // doesn't work
fancy_cast<int>.operator()<int>(1.5);  // works, but no one would do this

This is not the most efficient solution, but you can create a class that has a template parameter for the type to convert to, and then have a constructor template that takes any type. Then if you add an operator T for the type you instantiate the class with you can have that return correct value. That would look like

template<typename T>
struct fancy_cast
{
    T ret;
    template<typename U>
    fancy_cast(U u) : ret(u) {} // or whatever you want to do to convert U to T
    operator T() && { return std::move(ret); }
};

int main()
{
    double a = 0;
    int b = fancy_cast<int>(a);
}

This works because there is no way to specify the template parameter for the constructor since you can't actually call it.


I found a good-looking solution.

We can use a non-type parameter pack, of a type that the user can't construct.1 E.g. a reference to a hidden class:

namespace impl
{
    class require_deduction_helper
    {
      protected:
        constexpr require_deduction_helper() {}
    };
}

using require_deduction = impl::require_deduction_helper &;

template <typename A, require_deduction..., typename B>
A fancy_cast(B)
{
    return {};
}

1 We do have to leave a loophole for constructing a deduction_barrier, otherwise the code would be ill-formed NDR. That's why the constructor is protected.

Tags:

C++