Clang 无法在模板 class 特化中编译模板函数,该特化具有来自模板声明的 *distinct return 类型*
Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration
以下函数 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()
将值或指向值的指针的迭代器解引用为原始值。 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)
^~~~~~~~~~
谁能解释一下:
- 为什么CLang编译失败
derefItemX()
?
- 如何使用适用于不同编译器的另一种方法参数化对 *x 或 **x 取消引用的迭代器?
非常感谢!
注:
当指定 return 类型时,C++11 存在同样的问题,但 不同 在模板声明和特化中。
看起来 CLang 需要匹配 return 类型(模板 class 声明和特化中的模板函数),根据标准,它们不是函数签名的一部分。 @max66 指定的 "cross-compiler" 解决方案是模板的空声明 class 和所需的专业化。
我不知道如何笼统地解决问题;但是这个问题(如果我没记错的话)可以通过专门化整个 class; 来解决;像
#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
}
};
关于这个问题"why the clang fail to compile"...我很困惑,我不知道 g++ 和 clang++ 之间谁是对的
p.s.: 对不起我的英语不好
我最近使用 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;
}
以下函数 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()
将值或指向值的指针的迭代器解引用为原始值。 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)
^~~~~~~~~~
谁能解释一下:
- 为什么CLang编译失败
derefItemX()
? - 如何使用适用于不同编译器的另一种方法参数化对 *x 或 **x 取消引用的迭代器?
非常感谢!
注:
当指定 return 类型时,C++11 存在同样的问题,但 不同 在模板声明和特化中。
看起来 CLang 需要匹配 return 类型(模板 class 声明和特化中的模板函数),根据标准,它们不是函数签名的一部分。 @max66 指定的 "cross-compiler" 解决方案是模板的空声明 class 和所需的专业化。
我不知道如何笼统地解决问题;但是这个问题(如果我没记错的话)可以通过专门化整个 class; 来解决;像
#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
}
};
关于这个问题"why the clang fail to compile"...我很困惑,我不知道 g++ 和 clang++ 之间谁是对的
p.s.: 对不起我的英语不好
我最近使用 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;
}