2015-03-12 11 views
22

Ich suche nach einer Möglichkeit, bestimmte überlastete GCC-Einbauten in C++ zu simulieren. Die Einbauten sind ähnlich wie diese:Funktion, die nur Literal Ganzzahlen

__builtin_foo(char *a, signed int b); 
__builtin_foo(short *a, signed int b); 
__builtin_foo(long *a, signed int b); 

Mit einer speziellen Einschränkung schwer in GCC codiert: b eine wörtliche Wert sein muss, dh Sie können auch anrufen:

__builtin_foo((char *)0, 1); 

aber nicht:

extern int val; 
__builtin_foo((char *)0, val); 

, die einen Compilerfehler generiert. Ich habe mit std::enable_if fiedled, um dies zu simulieren, kann aber keine Möglichkeit finden, zu erzwingen, dass nur wörtliche Argumente akzeptiert werden. Gibt es eine Möglichkeit, dies zu tun?

+0

#define ASSERT_LITERAL (x) (void) (x ## 98765L) - bewirkt, dass ein Übersetzungsfehler für alle nicht Ganzzahlliteral z.B. ASSERT_LITERAL (x); - fehlgeschlagen ASSERT_LITERAL (1); - bestehen. Zu hacky, um als Antwort hinzuzufügen – samgak

+3

@samgak: Es ist auch zu hacky zu arbeiten. 'ASSERT_LITERAL (0)' wird ebenfalls fehlschlagen. –

+0

@MikeSeymour: Kleinere Details; 'x ## 010L' behebt das. Aber ich bin mir weniger sicher über 'ASSERT_LITERAL (0.0)' – MSalters

Antwort

15

Sie können Art simulieren sie mit einem Makro und den GCC intrinsische __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) 

Diese FOO(1) erlauben zu kompilieren, aber nicht int i = 1; FOO(i);

Allerdings hängt das Ergebnis von __builtin_constant_p auf der Optimierungsstufe Bei höheren Optimierungsebenen werden const Variablen als Konstanten behandelt, sodass sie nicht nur Literale akzeptieren.

Natürlich, wenn Sie bereit sind, Konstanten-Ausdrücke zuzulassen, nicht nur Literale, dann müssen Sie die Variable nur in einem Kontext verwenden, der einen Konstanten-Ausdruck erfordert, wie eine statische Assertion oder Typ Vorlage Argument.

+0

Das sieht gut aus, ich werde es versuchen. Eigentlich können die Builtins auch Konstanten akzeptieren, also wäre das das Gleiche wie beim C++ - Ansatz, aber es ist wirklich nicht wichtig im Anwendungsfall (dh Testen, ob die Auflösung der überladenen Builtins in C wie rsolution von C++ überladenen Funktionen funktioniert). – user3510167

+0

Außer, dass Gcc nicht static_assert() in einem Makro mag. :-( – user3510167

+0

@ user3510167: dann benutze einen der historischen Fallbacks, wie 'CHECKCONSTANT char [i] verwenden;' – MSalters

13

Sie könnten die Funktion in eine Vorlage drehen:

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

Die Aufrufsyntax dann builtin_foo<1>(whatever) wäre.

Wenn Sie das nicht wollen, können Sie die Vorlage in einem Makro wickeln könnten:

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

Dies wird natürlich akzeptieren jeden integralen konstanten Ausdruck, nicht nur ein wörtliche.

31

Hier ist eine portable C++ 11-Lösung, so dass Ihre Funktion (Makro tatsächlich, sorry) akzeptiert Literale integer nur und löst einen Fehler bei der Kompilierung statt:

constexpr int operator "" _literal(unsigned long long i) 
{ 
    return i; 
} 

#define m_builtin_foo(integer) builtin_foo(integer ## _literal) 

Benutzerdefinierte Literale nur Literale akzeptieren (daher ihr Name). Daher, wenn Sie Ihre Makro einfügen ein benutzerdefiniertes Literal, was an es übergeben wird, sollte akzeptieren nur die Literale von der entsprechenden benutzerdefinierten Literal akzeptiert.

Das ist jedoch ziemlich hässlich und ich denke, das könnte fehleranfällig sein. Nicht sicher wie.


@MichaelAnderson wies in den Kommentaren, dass m_builtin_foo(i+1) noch funktionieren würde. Stimmt. @Angew hat vorgeschlagen, den Rückgabetyp _literal in einen Wrapper zu schreiben, der nicht mit Ganzzahlarithmetik kompatibel ist und explizite Konvertierungen hinzufügt.Er war auch richtig, hier ist die vollständigere Lösung:

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)) 
+1

Kann sogar mit anderen Überladungen erweitert werden. Klug ! – Quentin

+3

Wow, das ist cool. – 0x499602D2

+4

Was ist mit 'm_builtin_foo (x + 1)'? –

Verwandte Themen