0

How would i use enable_if to disable the constructor if the function passed into the template does not contain valid arguments.

template <typename SrcType>
using is_Valid_Ret_Type = std::bool_constant<
    std::is_same<SrcType, void>::value |
    std::is_same<SrcType, int>::value>;

template <typename SrcType>
using is_Valid_Arg_Type = std::bool_constant<
    std::is_integral<SrcType>::value /*|
    std::is_same<SrcType, float>::value*/>;

template<typename Fn> class FunctionBase;
template<typename R, typename... Args>
class FunctionBase <R(__cdecl*)(Args...)>
{
    // ......
};

template <auto F>
class Function : public FunctionBase<decltype(F)> {
public:
    template <typename R, typename... Args>
    static R return_type_of(R(*)(Args...)) {};

    template<
        typename = std::enable_if_t<is_Valid_Ret_Type<decltype(return_type_of(F))>::value>,
        typename = std::enable_if_t<(is_Valid_Arg_Type<Args>::value&& ...)>> // how do I do this
    Function() : FunctionBase<decltype(F)>() { }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
docasok733
  • 117
  • 6
  • Does this answer your question? [SFINAE to select constructor based on class value template parameter](https://stackoverflow.com/questions/61544297/sfinae-to-select-constructor-based-on-class-value-template-parameter) – super May 13 '20 at 05:08
  • 1
    In this case you could also disable the whole class using partial specialization. – super May 13 '20 at 05:10
  • @super: link only partially answers OP's issue, OP seems to have difficulty to retrieve `Args` types from `F`. – Jarod42 May 13 '20 at 08:33

2 Answers2

0

You can use a helper function to check if all arguments are valid.

template <typename R, typename ... Args>
static auto are_args_valid(R(*)(Args...))
{
    return std::bool_constant<(true && ... && is_Valid_Arg_Type<Args>::value)>{};
}

In the above helper function, I am using a fold expression to check if each and every argument type is valid.

This can then be used inside enable_if to check if all arguments are valid, like so

    template<
        typename = std::enable_if_t<is_Valid_Ret_Type<decltype(return_type_of(F))>::value>,
        typename = std::enable_if_t<decltype(are_args_valid(F))::value>>
    Function() : FunctionBase<decltype(F)>() { }

Here is a demo on golbolt.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Empty Space
  • 743
  • 6
  • 17
0

Partial specialization might help in your case, mostly the same way as for the Base class:

template <auto F>
class Function;

template <typename R, typename... Args, R (*F)(Args...)>
class Function<F> : public FunctionBase<decltype(F)> {
public:
    static_assert(is_Valid_Ret_Type<R>::value);
    static_assert((true && ... && is_Valid_Arg_Type<Args>::value));

    Function() : FunctionBase<decltype(F)>() { }
};

Your SFINAE attempt also failed as condition has been fixed by the class, producing hard error instead of SFINAE.

Jarod42
  • 203,559
  • 14
  • 181
  • 302