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

为君一笑 提交于 2019-12-10 13:22:25

问题


The following function derefItemX() is compiled fine on GCC 4.8-5.3, but fails on 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. CLang shows the following error message: that says not much:

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()?
  2. How to parameterize an iterator dereferencing to either *x or **x using another approach that would work on different compilers?

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.
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. The "cross-compiler" solution as specified by @max66 is to have an empty declaration of the template class and required specializations.


回答1:


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++

p.s.: sorry for my bad English




回答2:


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):

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


来源:https://stackoverflow.com/questions/38054055/clang-fails-to-compile-template-function-in-a-template-class-specialization-whi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!