Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

std::enable_if for std::is_integral and its negation both show as ambiguous candidate overloads

I have some API that serializes values. I have created a wrapper that helps by having a simple one method that should accept all supported types.

Most types require explicit implementation, but all integer types are accepted by single method on that API. I wrote this code:

// Used to allow for human readable error on missing overload
template<typename T>
struct fail_if_invoked : std::false_type
{ };

// This overload should get selected if value is not integer type and explicit overload does not exist
template<typename TVal, typename std::enable_if<!std::is_integral<TVal>::value>::type* = nullptr>
void accept_value(TVal && vadd)
{
    static_assert(fail_if_invoked<TVal>::value, "Missing implementation for this type");
}

// This overload should handle all integer types
template<typename TInteger, typename std::enable_if<std::is_integral<TInteger>::value>::type* = nullptr>
void accept_value(TInteger num)
{
    ...
}

void accept_value(const char*) 
{
    ...
}

However, when unsigned int is the argument to accept_value, I get an error about ambiguous call, for these overloads:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

my_helper.h:37:10: note: candidate function [with TVal = unsigned short &, $1 = nullptr]
    void accept_value(TVal && vadd)
         ^
my_helper.h:44:10: note: candidate function [with TInteger = unsigned short, $1 = nullptr]
    void accept_value(TInteger num)
         ^
my_helper.h:59:10: note: candidate function
    void accept_value(double num)
         ^
my_helper.h:79:10: note: candidate function
    void accept_value(bool num)

I sort of understand the bool and double, although it wasn’t an issue when I had explicit overloads for everything. But why is the void add_value(TVal && vadd) still in the list when !std::is_integral<TVal> should disable it?

And is it even possible to have generic implementation for all integral types while also having bool and double overloads?

>Solution :

You need to wrap the template parameter in std::decay_t to get the raw type without any reference or const, because std::integral<int&> will evaluate to false.

Update – addition explanation

The signature accept_value(TVal && vadd) accepts the parameter using an rvalue-reference (often called a universal reference). If you pass a variable of type int, TVal will deduce to int&. If you pass a literal integer like 1, TVal will deduce to int. Without the std::decay_t, this will cause different results when std::is_integral is evaluated. Overload resolution will behave accordingly.

End Update

Sample Code

#include <iostream>

// Used to allow for human readable error on missing overload
template<typename T>
struct fail_if_invoked : std::false_type
{ };

// This overload should get selected if value is not integer type and explicit overload does not ex\
ist
template<typename TVal,
         typename std::enable_if<!std::is_integral<std::decay_t<TVal>>::value>::type* = nullptr>
void accept_value(TVal && vadd)
{
    static_assert(fail_if_invoked<TVal>::value, "Missing implementation for this type");
}

// This overload should handle all integer types
template<typename TInteger,
         typename std::enable_if<std::is_integral<std::decay_t<TInteger>>::value>::type* = nullptr>
void accept_value(TInteger num)
{
}

int main(int argc, const char *argv[]) {
    int a{};
    accept_value(a);
    accept_value(1);
    accept_value("char");
    return 0;
}

Output

/work/so/scratch/src/p1.cpp:16:5: error: static assertion
      failed due to requirement 'fail_if_invoked<const char (&)[5]>::value': Missing
      implementation for this type
    static_assert(fail_if_invoked<TVal>::value, "Missing implementation for this type");
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/work/so/scratch/src/p1.cpp:30:5: note: in instantiation of
      function template specialization 'accept_value<const char (&)[5], nullptr>' requested here
    accept_value("char");
    ^
1 error generated.
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading