c++gccclangcstdint

Why Clang and GCC complain about this specific situation


I have this code:

#include <string>
#include <cstdint>

typedef unsigned long long u64;

struct A{
    A(int a) : m_a(a){}
    A(u64 a) : m_a(a){}
    A(double a) : m_a(a){}
    u64 m_a;
};

struct B{
    B(int b) : m_b(b){}
    B(uint64_t b) : m_b(b){}
    B(double b) : m_b(b){}
    uint64_t m_b;
};

int main(){
    
    // This works
    unsigned long long a = std::stoull("10000");
    
    // And this
    auto a2 = A(a);

    // And this
    auto a3 = A(std::stoull("10000"));
    


    // This works
    uint64_t b = std::stoull("10000");
    
    // And this
    auto b2 = B(b);

    // But not this?
    auto b3 = B(std::stoull("10000"));

    return 0;
}

Godbolt

Why does Clang and GCC complain about the very last example? Shouldn't it be the same as the third example? Can someone explain what is going on? What C++ features/rules are at play here?


Solution

  • On the platform you are compiling, uint64_t is unsigned long, not unsigned long long.

    You may be interested in https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models .

    Why does Clang and GCC complain about the very last example?

    They tell you why - the call is ambiguous, it is not clear which overload to choose.

    Shouldn't it be the same as the third example?

    No. In the third case class A has a unsigned long long overload. In the last case class B does not have unsigned long long overload.