2016-04-04 28 views
13

Daha iyi bir başlık bulamadım, ancak doğru fikre sahipseniz bunu değiştirmek için çekinmeyin. Olduğu gibi, GCC vs clang zaten daha iyidir.Variadic şablonlar ve işlevler 'işaretçiler: hangi derleyici doğru?


Bu kodda neyin yanlış olduğunu anlamaya çalışıyorum:

template <typename... T> 
struct S; 

template <typename T, typename... U> 
struct S<T, U...>: S<U...> { 
    using S<U...>::f; 

    template<void(*F)(const T &)> 
    void f() { } 
}; 

template<> 
struct S<> { 
    void f(); 
}; 

template<typename... T> 
struct R: S<T...> { 
    using S<T...>::f; 

    template<typename U, void(*F)(const U &)> 
    void g() { 
     this->template f<F>(); 
    } 
}; 

void h(const double &) { } 

int main() { 
    R<int, double> r; 
    r.g<double, h>(); 
} 

O ile GCC 4.9 (here bakınız) derler, ama clang 3.8 ile derleme değil .0 (bkz. here). Hangi derleyici

sağ ve neden?
Ayrıca, hem derleyicilerle derleme kodunu görmek için ne yapabilirim?

+0

(hala test) ve şimdi i sorusuna bayrak "variadic-şablonları" add önerebilirsiniz. – Radek

+0

Bu ICC de bunu derlemek için başarısız görünüyor: https: //godbolt.org/g/N67e2z – NathanOliver

+0

Belki bu soru ile ilgili olabilir (http://stackoverflow.com/questions/8629839/c-candidate-template-ignored -doğru-açık-belirtilen-argüman-için-templ) veya [bu soru] (http://stackoverflow.com/questions/33872039/invalid-explicitly-specified-argument-in-clang-but-successful-compilation-in GCC)? – callyalater

cevap

9

O çınlama burada doğru olduğundan ve bu bir gcc hata olduğunu düşünüyoruz.

struct U { 
    template<int > void foo() { } 
}; 

struct X : U { 
    using U::foo; 
    template<void* > void foo() { } 
}; 

int main() { 
    X{}.foo<1>(); // gcc ok, clang error 
} 

[namespace.udecl]: From: İlk olarak, basitleştirilmiş bir örnekle başlayalım

zaman bir türetilmiş sınıfa Temel sınıftan beyanlarını, üye fonksiyonları ve üye işlev şablonları getirir-beyanname kullanılarak türetilmiş sınıf geçersiz kılma ve/veya gizleme elemanı fonksiyonları ve aynı isimde şablonları elemanı işlevi, parametre tip listesi (8.3.5), ev yeterlilik ve temel sınıf ref-niteleyici (eğer varsa) (çatışmak yerine). Böyle gizli veya geçersiz beyanlar kullanarak-beyanname tarafından tanıtılan bildirimleri kümesinden dışlanır. , Ev yeterlilik (yok) ve ref eleme (yok);

U::foo ve X::foo aynı isim, parametre-tip listesi ( yok ve kama) sahiptir. Dolayısıyla, X::fooyüklenerek yerineU::foo gizler ve kesinlikle X::foo içine yanlış türde geçiyoruz.

Basitçe farklı fonksiyon işaretçisi türlerinde aşırı yüklenme (ziyade şablon parametreleri olarak onları alarak)

çalışıyor:

template <typename T, typename... U> 
struct S<T, U...> : S<U...> { 
    using S<U...>::f; 

    void f(void (*F)(const T&)) { } 
}; 

Yoksa gerçekten şablon argümanları olarak işlev işaretçileri gerekiyorsa, yine aşırı yük ile bunları sarabilirdiniz etiket türü:

template <class T> 
using fptr = void(*)(const T&); 

template <class T, fptr<T> F> 
using func_constant = std::integral_constant<fptr<T>, F>; 

ve yayılması:

template <typename T, typename... U> 
struct S<T, U...>: S<U...> { 
    using S<U...>::f; 

    template <fptr<T> F> 
    void f(func_constant<T, F>) { } 
}; 

ve:

template <class U, fptr<U> F> 
void g() { 
    this->f(func_constant<U, F>{}); 
} 

ve kama;parameter-type-list'un tanımı şablon parametrelerinden [email protected] sonra

+0

Ancak parametre türü listesi, şablon bildirimlerinden gelen parametre paketlerinden bahsediyor. Öyleyse, bu, şablonların aşırı yüklenme ve saklanma için fonksiyon çözünürlüğünde dikkate alınacağı anlamına gelmiyor mu? – callyalater

+0

@callyalater Ancak bir parametre paketi hala bir parametredir. Bir şablon argümanı değil. – Barry

+0

@Barry Bir tür etiket gönderimi, değil mi? Aynı şeyi düşündüm, ama en uygun çözümün olup olmadığını merak ediyordum. Detaylı yanıt için teşekkür ederiz (her zamanki gibi, gerçekten takdir). – skypjack

3

- için S uzmanlık f tanımını değiştirerek:

template <typename T, typename... U> 
struct S<T, U...>: S<U...> { 
    using S<U...>::f; 


    template<void(*F)(const T &)> 
    void f(T *= nullptr) { } 
}; 

da koduyla çalışma tınlamak yapar.

Düzenleme:

template <typename T, typename... U> 
struct S<T, U...>: S<T>, S<U...> { 
}; 

template<typename T> 
struct S<T> { 
    template<void(*F)(const T &)> 
    void f() { } 
} 

Sonra kullanarak g içinde f yöntemi çağırmak:

S<U>::template f<F>(); 

kullanma

kod daha da basit size uzmanlık değiştirebilir hale getirmek için Bu seçenek bir adım daha ileri gidebilir ve @barry önerilen bir etiket kullanma önerisinde bulundu. yerine bir fonksiyonun bir Paramtre olarak daha n şablon parametresi: Tuhaf

template <typename... T> 
struct S; 

template <typename T> 
struct footag { }; 

template <typename T, typename... U> 
struct S<T, U...>: S<footag<T>>, S<U...> { 
}; 

template<typename T> 
struct S<T>:S<footag<T>> { 
}; 

template<typename T> 
struct S<footag<T>> { 
    template <void (*F)(const T&)> 
    void f() { } 
}; 

template<typename V, typename... T> 
struct R: S<V, T...> { 
    template<typename U, void(*F)(const U &)> 
    void g() { 
     S<footag<U>>::template f<F>(); 
    } 
}; 

void h(const float &) { } 

int main() { 
    R<int, float, double> r; 
    r.g<float, h>(); 
} 
+1

Eh, 'NULL' yerine' nullptr' daha fazla olurdu * C++ 11 * -ish, değil mi? – skypjack

+0

Elbette ki ... :) Düzenleme Yapma –

+0

Etiket gönderimine güvenmeyi tahmin ediyorum, daha hoş bir çözüm. Önerdiğiniz şey daha çok miks tabanlı bir yaklaşıma benziyor, ama aradığım şey bu değil (yanlış anlama, mixin'i gerçekten çok seviyorum ama bu onları kullanacağım sorun değil). Mantıklı geliyor? – skypjack