2017-07-20 4 views
-1

Ou du moins je le pense. Considérez le code suivantCRTP Pourquoi le moteur de recherche de membre est-il en cours d'exécution?

#include <iostream> 
#include <memory> 

struct BaseBase { 
    virtual void foo() = 0; 
    virtual ~BaseBase(){} 
}; 

template <typename Derived> 
struct Base : BaseBase{ 
    void foo() override{ 
     static_cast<Derived*>(this)->foo(); 
    } 
}; 

struct D1 : Base<D1> {}; 
struct Unrelated {}; 

// no runtime polymorphism 
template <typename SDerived> 
struct SBase{ 
    void foo() { 
     static_cast<SDerived*>(this)->foo(); 
    } 
}; 

struct SD1 : SBase<SD1> {}; 


template <typename T, typename ...Args> 
void doFoo(Args&&... args){ 
    T* t = new T(std::forward<Args>(args)...); 
    t->foo(); 
} 

int main(){ 
    doFoo<Unrelated>(); //compile time error, foo not found in unrelated 
    doFoo<SD1>(); //runtime crash 
    doFoo<D1>(); //runtime crash 
    return 0; 
} 

J'espérais que le compilateur serait assez gentil pour vérifier l'existence de foo au moment de la compilation dans doFoo mais dans les deux cas, avec virtual dans la base, et sans virtual dans la base du code compile bien mais se bloque à l'exécution.

Pourquoi est-ce?

Edit: configuration clang

clang version 4.0.1 (tags/RELEASE_401/final) 
Target: x86_64-unknown-linux-gnu 

avec doFoo<Unrelated>() commentées compiles.

et g ++ configuration

gcc version 7.1.1 20170630 (GCC) 

avec doFoo<Unrelated>() compile commenté.

+1

Dans son état actuel, je ne pense pas que ce code devrait compiler. Il y a un problème évident avec la définition de 'SD1'. La classe CRTP 'SBase' essaie d'appeler la fonction membre' foo' de 'SDerived'. Mais quand il est instancié avec 'SD1' comme paramètre de modèle, cette fonction membre n'existe pas. Donc, ce programme est mal formé. Je ne pense pas que gcc ou clang compilerait ce programme sans erreurs. Pouvez-vous confirmer que c'est bien le code qui compile et produit un plantage d'exécution? –

+1

@ChrisBeck Lorsque 'SBase :: foo()' est appelé, il essaie en effet d'appeler 'foo' sur le pointeur' SDerived * '. Dans ce cas, 'SDerived' est' SD1'. Et 'SD1' a un membre' foo' qui peut être appelé. Il se trouve être le membre hérité 'SBase :: foo'. – aschepler

+1

@aschepler: Merci, c'est assez dommage pour l'auteur du code –

Répondre

3

Cela est dû au fait que les deux classes ont une fonction appelée foo. Il est présent dans la classe de base pour chaque classe. Cependant, toute cette fonction s'appelle elle-même, ce qui finit par provoquer un débordement de pile.

+0

Comment ai-je manqué cela, le compilateur voit un truc dans les deux classes car il est visible dans la structure parente ... ne codez pas à 2 heures du matin:) – arynaq