2016-06-27 15 views
6

Chức năng derefItemX() sau được biên dịch tốt trên GCC 4,8-5,3, nhưng không thành công trên Clang 3.8:Clang thất bại trong việc biên dịch mẫu chức năng trong một chuyên môn hóa lớp mẫu, trong đó có * biệt kiểu trả về * từ mẫu khai

//! Accessory Operations - template argument depended wrappers 
template<bool SIMPLE> // For Nodes/non-scoped storage 
struct Operations { 
    //! \brief Defererence wrapped or direct iterator 
    //! 
    //! \param iel IItemXT& - iterator to be dereferenced 
    //! \return ItemT& - resulting reference 
    template<typename IItemXT> 
    constexpr static auto& derefItemX(IItemXT& iel) 
    { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
      , "derefItemX(), IItemXT must be a forward iterator type"); 
     return **iel; // Dereference an iterator of pointer to the value 
    } 
}; 

//! Specialization for non-scoped storage (direct pointers) 
template<> 
template<typename IItemXT> 
constexpr auto& Operations<true>::derefItemX(IItemXT& iel) 
{ 
    static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
     , "derefItemX(), IItemXT must be a forward iterator type"); 
    return *iel; // Dereference an iterator of value to the value 
} 


... 
// Usage: 
auto& el = Operations<!is_pointer<typename IItemXT::value_type> 
      ::value>::derefItemX(ic); 

derefItemX() dereferences một trình lặp của giá trị hoặc con trỏ tới giá trị đến giá trị ban đầu. Clang hiển thị thông báo lỗi sau: nói rằng không nhiều:

include/hierarchy.hpp:168:35: error: out-of-line definition of 'derefItemX' does not match any declaration in 'XXX::Operations<true>' 
constexpr auto& Operations<true>::derefItemX(IItemXT& iel) 
            ^~~~~~~~~~ 

Ai có thể vui lòng giải thích:

  1. Tại sao Clang thất bại trong việc biên dịch derefItemX()?
  2. Làm cách nào để tham số hóa một cuộc hội thảo lặp lại thành * x hoặc ** x bằng cách sử dụng một cách tiếp cận khác có thể hoạt động trên các trình biên dịch khác nhau?

Cảm ơn rất nhiều!

Lưu ý:
Vấn đề tương tự tồn tại cho C++ 11 khi kiểu trả về được chỉ định, nhưng khác trong việc kê khai và chuyên môn hóa mẫu.
Có vẻ như CLang yêu cầu phải khớp với kiểu trả về (của các hàm mẫu trong khai báo lớp mẫu và chuyên môn), không phải là một phần của chữ ký hàm theo tiêu chuẩn. Giải pháp "biên dịch chéo" theo quy định của @ max66 là có khai báo trống của lớp mẫu và các chuyên môn bắt buộc.

+1

với prope r [mcve], bạn có thể nhận thêm trợ giúp. – AndyG

+1

Chức năng chuyên môn là một ý tưởng khủng khiếp. * luôn luôn * chuyên lớp, hoặc các hàm quá tải ở phạm vi không gian tên. – o11c

+0

@ o11c vì bạn có thể thấy lớp học chuyên biệt, không phải là hàm, bởi vì chuyên môn hóa một phần các hàm không được phép theo tiêu chuẩn. Quá tải là một tùy chọn trong một số trường hợp, nhưng không phải cho mã hiệu suất cao, khi việc sử dụng (các) Bảng ảo ảnh hưởng đến tốc độ thực thi tổng cộng. – luart

Trả lời

4

Tôi không biết cách giải quyết vấn đề một cách tổng quát; nhưng vấn đề này (nếu tôi không sai) có thể được giải quyết toàn bộ lớp học; cái gì đó như

#include <iterator> 
#include <type_traits> 

using namespace std; 

template <bool> 
struct Operations; 

template<> 
struct Operations<false> { 
    template<typename IItemXT> 
     constexpr static auto& derefItemX(IItemXT& iel) 
     { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
         , "derefItemX(), IItemXT must be a forward iterator type"); 
     return **iel; // Dereference an iterator of pointer to the value 
     } 
}; 

template<> 
struct Operations<true> { 
    template<typename IItemXT> 
     constexpr auto& derefItemX(IItemXT& iel) 
     { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
         , "derefItemX(), IItemXT must be a forward iterator type"); 
     return *iel; // Dereference an iterator of value to the value 
     } 
}; 

Về vấn đề "tại sao kêu vang không biên dịch" ... Tôi bối rối và tôi không biết whos ngay giữa g ++ và kêu vang ++

ps: xin lỗi cho tiếng Anh xấu của tôi

+0

Cảm ơn bạn Max! Bạn nói đúng, chuyên môn hóa đầy đủ hoạt động trên tất cả các trình biên dịch! – luart

+0

@luart - Cảm ơn bạn: cố gắng hiểu vấn đề của bạn Tôi đã khám phá những điều về C++ 14 mà tôi chưa từng nghi ngờ; vẫn còn hiểu tại sao g ++ biên dịch ví dụ của bạn anc clang ++ không; Tôi đã có một ý tưởng nhưng đã sai – max66

0

Gần đây tôi đã viết lại rằng mẫu sử dụng std::enable_if<>, hoạt động tốt trên tất cả các trình biên dịch và giải quyết vấn đề một cách duyên dáng hơn nhiều (không có tham số rõ ràng):

//! \brief Defererence wrapped or direct iterator 
//! 
//! \param iel IItemXT - iterator to be dereferenced 
//! \return ItemT& - resulting reference 
template <typename IItemXT, enable_if_t<is_pointer<typename iterator_traits<IItemXT>::value_type>::value>* = nullptr> 
constexpr auto derefIterX(IItemXT iel) -> remove_pointer_t<typename iterator_traits<IItemXT>::value_type>& 
{ 
    static_assert(is_iterator<IItemXT>(), "derefIterX(), IItemXT must be a forward iterator type"); 
    return **iel; 
} 

template <typename IItemXT, enable_if_t<!is_pointer<typename iterator_traits<IItemXT>::value_type>::value, bool>* = nullptr> 
constexpr auto derefIterX(IItemXT iel) -> typename iterator_traits<IItemXT>::reference 
{ 
    static_assert(is_iterator<IItemXT>(), "derefIterX(), IItemXT must be a forward iterator type"); 
    return *iel; 
} 
Các vấn đề liên quan