2013-04-07 14 views
8

Odpowiadając this question, próbowałem następujący kod z GCC (code compiled) i szczęk (code rejected):constexpr statyczny wskaźnik do funkcji, różnica między kompilatory

typedef long (*func)(int); 

long function(int) { return 42; } 

struct Test 
{ 
    static constexpr func f = &function; 
}; 

template<func c> 
struct Call 
{ 
    static void f() 
    { 
     c(0); 
    } 
}; 

int main() 
{ 
    Call<Test::f>::f(); 
} 

Nie jestem pewien, które kompilator ma rację, chociaż myślę, że inicjalizacja constexpr Test::f jest w porządku. Wyjścia błąd dzyń jest:

error: non-type template argument for template parameter of pointer type 'func' 
     (aka 'long (*)(int)') must have its address taken 
  1. Który kompilator ma rację?
  2. Jeśli clang ma rację, dlaczego i co ten błąd naprawdę oznacza?

EDIT bo "dlaczego", patrz DyP's question.

+0

Zastanawiam się, czy nie '& zakresie funkcji jest rzeczywiście ważne dla inicjatora' constexpr'. Oba kompilatory wydają się tak sądzić. Ale wydaje mi się to niemiłą. Nie jest to znane podczas kompilacji, tylko w czasie łączenia. – Omnifarious

+0

'& function' jest adresem funkcji, więc dla mnie jest znana w czasie kompilacji ... Na przykład można przekazać wskaźnik do funkcji jako argument szablonu. – Synxis

+1

Wskaźnik do funkcji to jedno ... jeśli na przykład jest to część biblioteki współdzielonej, w jaki sposób adres mógł zostać zakwalifikowany jako "constexpr"? –

Odpowiedz

8
argumenty

14.3.2 szablon dla typu [temp.arg.nontype]

z matrycą argumentem non-typu nie-szablon szablon parametr powinien być:

[...]

- wyrażenie stałe (5.19), które oznacza adres obiektu z pamięcią statyczną> czas trwania i połączenie zewnętrzne lub wewnętrzne lub funkcję z zewnętrznym lub wewnętrznym łącznikiem, w tym szablony funkcji i szablon funkcji -ids ale excl zdenerwowanie niestatycznych elementów klasy, wyrażone (ignorowanie nawiasów) jako & id-expression, z tym wyjątkiem, że & można pominąć, jeśli nazwa odnosi się do funkcji lub macierzy i należy je pominąć, jeśli odpowiedni parametr-szablonu jest odniesieniem; [...]

(n3485, moje podkreślenie)

Nie wiem dokładnie, dlaczego to było ograniczone, ale myślę, że może to być związane z faktem, że adres funkcja nie jest dostępna w czas kompilacji (może być substytutem dla celów tworzenia szablonów).


Edit: Zwiększona odpowiedź wynika z obserwacji pytanie (komentarz) o SynXis

constexpr func = &function; 

^to jest dobrze uformowane; możesz użyć adresu funkcji do zainicjowania obiektu constexpr. Problemem jest to, że jest to wyraźnie zabronione użyć wskaźników jako argumentów typu non-szablonu innych niż formy &identifier:

using My_Call  = Call < &function >; // fine 

constexpr func mypointer = &function; // fine 
using My_Ind_Call = Call <func>;  // forbidden, argument not of form `&id` 
+3

To wydaje się niedopatrzenie. Jeśli przypiszesz 'constexpr' rzecz do' constexpr', a następnie przypiszesz to do innego 'constexpr', to powinno być przechodnie. – Omnifarious

+3

@Nowoczesny To ** jest ** "constexpr". Ale jest jawnie zabronione jako szablonowy argument nie typu. – dyp

+0

Cóż, to interesujące. Jawnie nie traktowane w sposób ortogonalny. Zastanawiam się, co to jest rozumowanie. Chociaż mam silne podejrzenia. Domyślam się, że obiekty, które mogą zostać przeniesione przez linker, są przywoływane po nazwie w regułach dotyczących szablonów. Wymuszanie kompilatorów noszenia oryginalnej nazwy dla 'constexpr' takich rzeczy jest raczej uciążliwe i prawdopodobnie niemożliwe w niektórych scenariuszach. – Omnifarious

Powiązane problemy