简体   繁体   English

Clang无法在模板类专门化中编译模板函数,该类具有与模板声明不同的返回类型

[英]Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration

The following function derefItemX() is compiled fine on GCC 4.8-5.3, but fails on CLang 3.8: 以下函数derefItemX()在GCC 4.8-5.3上编译良好,但在CLang 3.8上失败:

//! 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 an iterator of either a value or a pointer to the value to original value. derefItemX()取消引用值的迭代器或将值指向原始值的指针。 CLang shows the following error message: that says not much: CLang显示以下错误消息:内容不多:

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)
                                  ^~~~~~~~~~

Can anybody please explain: 谁能解释一下:

  1. Why does CLang fail to compile derefItemX() ? 为什么CLang无法编译derefItemX()
  2. How to parameterize an iterator dereferencing to either *x or **x using another approach that would work on different compilers? 如何使用另一种适用于不同编译器的方法来对迭代器进行参数化,使其引用* x或** x?

Thanks a lot! 非常感谢!

Note: 注意:
The same problem exists for C++11 when the return type is specified, but differs in the template declaration and specialization. 指定返回类型时,C ++ 11存在相同的问题,但模板声明和特殊化有所不同
Looks like CLang requires to match the return types (of template functions in the template class declaration and specialization), which are not part of the function signature according to the standard. 看起来CLang需要匹配返回类型(模板类声明和特殊化中的模板函数的返回类型),根据标准,它们不属于函数签名。 The "cross-compiler" solution as specified by @max66 is to have an empty declaration of the template class and required specializations. @ max66指定的“交叉编译器”解决方案是对模板类和所需的特殊化具有空声明。

I don't how to solve the problem in a general way; 我不是一般性地解决问题的方法。 but this problem (if I'm not wrong) could be solved specializing the entire class; 但是这个问题(如果我没记错的话)可以解决整个班级的问题; something like 就像是

#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
       }
};

Regarding the problem "why the clang fail to compile"... i'm confused and I don't know whos right between g++ and clang++ 关于“为什么clang无法编译”的问题...我很困惑,我不知道谁在g ++和clang ++之间

ps: sorry for my bad English ps:对不起,我的英语不好

I recently rewrote that template using std::enable_if<> , which works fine on all compilers and solves the problem much gracefully (without the explicit parameter): 我最近使用std::enable_if<>重写了该模板,该模板在所有编译器上都可以正常工作,并且很好地解决了问题(没有显式参数):

//! \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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM