function that takes only literal integers

后端 未结 3 1850
一生所求
一生所求 2021-01-03 22:30

I\'m looking for a way to simulate certain overloaded GCC built-ins in C++. The built-ins are similar to these:

__builtin_foo(char *a, signed int b);
__buil         


        
相关标签:
3条回答
  • 2021-01-03 22:36

    You can sort of simulate it using a macro and the GCC intrinsic __builtin_constant_p

    constexpr int foo(int i) { return i; }
    
    #define FOO(i) do { \
      static_assert(__builtin_constant_p(i), "Not a constant"); \
      foo(i); \
    } while (false)
    

    This will allow FOO(1) to compile, but not int i = 1; FOO(i);

    However, the result of __builtin_constant_p depends on the optimisation level, at higher levels of optimisation const variables are treated as constants, so it doesn't only accept literals.

    Of course if you're willing to allow constant-expressions, not just literals, then all you have to do is use the variable in a context that requires a constant-expression, such as a static assertion or a non-type template argument.

    0 讨论(0)
  • 2021-01-03 22:37

    Here is a portable C++11 solution so that your function (macro actually, sorry) accepts only integer literals and triggers a compile-time error instead:

    constexpr int operator "" _literal(unsigned long long i)
    {
        return i;
    }
    
    #define m_builtin_foo(integer) builtin_foo(integer ## _literal)
    

    User-defined literals accept only literals (hence their name). Therefore, if you make your macro paste a user-defined literal to what is passed to it, it should only accept the literals accepted by the corresponding user-defined literal.

    However, that's rather ugly and I guess that could be error-prone. Not sure how though.


    @MichaelAnderson pointed in the comments that m_builtin_foo(i+1) would still work. That's right. @Angew suggested wrapping the return type of _literal in a wrapper incompatible with integer arithmetic and adding explicit conversions. He was also right, here is the more complete solution:

    struct wrapper
    {
        constexpr wrapper(int n):
            value{n}
        {}
    
        explicit constexpr operator int() const
        {
            return value;
        }
    
        int value;
    };
    
    constexpr wrapper operator "" _literal(unsigned long long i)
    {
        return { int(i) };
    }
    
    #define m_builtin_foo(integer) builtin_foo(int(integer ## _literal))
    
    0 讨论(0)
  • 2021-01-03 23:00

    You could turn the function into a template:

    template <int b>
    builtin_foo(char *a);
    

    The call syntax would then be builtin_foo<1>(whatever).

    If you don't like this, you could wrap the template in a macro:

    #define m_builtin_foo(a, b) builtin_foo<(b)>((a))
    

    This will of course accept any integral constant expression, not just a literal.

    0 讨论(0)
提交回复
热议问题