template template parameters and clang

2019-02-13 16:24发布

问题:

I have had problems (possibly mine) with template template parameters and clang. The following toy example compiles and runs under g++ 4.7.0, not clang++ 3.0 (based on LLVM 3.0), both ubuntu 12.04.

Toy example (test_1.cpp):

#include <iostream>                                                                                 
#include <memory>                                                                                   

struct AFn                                                                                          
{                                                                                                   
   void operator()()                                                                                
     {                                                                                              
    ; // do something                                                                               
     }                                                                                              
};                                                                                                  

template<typename T>                                                                                
  struct impl                                                                                       
{                                                                                                   
   T *backpointer_;                                                                                 
};                                                                                                  

template<typename S, template <typename> class T>                                                   
  struct implT                                                                                      
{                                                                                                   
   T<S> *backpointer_;                                                                              
};                                                                                                  

template<typename>                                                                                  
  class AClass;                                                                                     

template<>                                                                                          
  struct implT<AFn, AClass>                                                                         
{                                                                                                   
   implT(std::string message) :                                                                     
     message_(message)                                                                              
       {}                                                                                           

   void operator()()                                                                                
     {                                                                                              
    std::cout << " : " << message_ << std::endl;                                                    
     }                                                                                              

   std::string message_;                                                                            
};                                                                                                  


template<typename Fn>                                                                               
class AClass                                                                                        
{                                                                                                   
 private:                                                                                           
   std::shared_ptr<implT<Fn, AClass> > p_;                                                          
 public:                                                                                            
   AClass(std::string message) :                                                                    
     p_(std::make_shared<implT<Fn, AClass> >(message))                                              
       {}                                                                                           
   void call_me()             
     {                                                                                              
    p_->operator()();                                                                               
     }                                                                                              
};                                                                                                  


int main(int argc, char **argv)                                                                     
{                                                                                                   
   AClass<AFn> *A = new AClass<AFn>("AClass<AFn>");                                                 
   A->call_me();                                                                                    

   delete A;                                                                                        

   return 0;                                                                                        
}                                                                                           

clang output:

*****@ely:~$ clang++ -std=c++11 test_1.cpp -o test_1
test_1.cpp:47:30: error: template argument for template template parameter must be a class template or
      type alias template
   std::shared_ptr<implT<Fn, AClass> > p_;
                         ^
test_1.cpp:47:40: error: C++ requires a type specifier for all declarations
   std::shared_ptr<implT<Fn, AClass> > p_;
                                   ^~
test_1.cpp:50:36: error: template argument for template template parameter must be a class template or
  type alias template
 p_(std::make_shared<implT<Fn, AClass> >(message))
                               ^
3 errors generated.
                                                                                        I can't make sense of the first error. It compiles and runs fine with gcc/g++ 4.7.0. Any help would be appreciated.        

回答1:

As noted, it's a Clang bug. AClass there is an injected-class-name, a unique grammatical construct which is both a class-name and a template-name.

Another workaround is to say AClass::template AClass. This avoids needing to qualify AClass with its enclosing namespace.



回答2:

The same thing happens for me with Clang 3.3.

The solution -- or workaround -- from this SO question is to replace AClass with ::AClass on lines 47 and 50, and then it compiles happily.

To be honest template template parameters make my head hurt. The referenced question suggests it's a Clang bug, but I'm not enough of an expert to be able to say.