gpt4 book ai didi

c++ - CRTP 类中成员函数的可见性

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:47:26 26 4
gpt4 key购买 nike

我正在编写一个带有排序函数对象的排序库。主要类之一 sorter_facade 旨在根据已经存在的重载向排序器提供一些 operator() 重载。下面是一个简单的 heap_sorter 对象简化示例,实现了堆排序:

struct heap_sorter:
sorter_facade<heap_sorter>
{
using sorter_facade<heap_sorter>::operator();

template<typename Iterator>
auto operator()(Iterator first, Iterator last) const
-> void
{
std::make_heap(first, last);
std::sort_heap(first, last);
}
};

sorter_facade 最简单的目标之一是在已经存在采用一对迭代器的重载时为排序器的 operator() 提供可迭代的重载。这是 sorter_facade 的简化实现,足以解决手头的问题:

template<typename Sorter>
struct sorter_facade
{
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<
not has_sort<Sorter, Iterable>,
decltype(std::declval<Sorter&>()(std::begin(iterable), std::end(iterable)))
>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};

在这个类中,has_sort 是一个特征,用于检测排序器是否具有采用 Iterable&operator() 重载。它是使用 detection idiom 的手动版本实现的:

template<typename Sorter, typename Iterable>
using has_sort_t = std::result_of_t<Sorter(Iterable&)>;

template<typename Sorter, typename Iterable>
constexpr bool has_sort = std::experimental::is_detected_v<has_sort_t, Sorter, Iterable>;

现在,针对实际问题:以下 main 与 g++ 5.2 配合良好:

int main()
{
std::vector<int> vec(3);
heap_sorter{}(vec);
}

然而,it fails with clang++ 3.7.0 ,并出现以下错误消息:

main.cpp:87:5: error: no matching function for call to object of type 'heap_sorter'
heap_sorter{}(vec);
^~~~~~~~~~~~~

/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with Iterable = std::vector<int, std::allocator<int> >]
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^

main.cpp:75:10: note: candidate function template not viable: requires 2 arguments, but 1 was provided
auto operator()(Iterator first, Iterator last) const
^

1 error generated.

显然,在评估 std::enable_if_t 时,它似乎认为 Sorter 已经有一个 operator() 能够接受一个Iterable&,这可能意味着 clang++ 和 g++ 在检查是否存在重载时不会对“相同的”Sorter 求值。

对于这个简单的例子,删除 std::enable_if_t 可以让整个事情正常进行,但是类 sorter_facade 实际上比那个大得多,我需要它来解决operator() 的其他重载存在歧义问题,因此仅删除它不是解决方案。

那么……是什么导致了错误?编译器应该接受还是拒绝这段代码?最后,是否有一种标准兼容的方法可以使它与最新版本的 g++ 和 clang++ 一起工作?


编辑: 作为旁注,我设法通过添加另一层黑魔法 以至于我根本不知道它为什么还能用。虽然前面的所有问题都存在,但这里是“解决方法”(使用 C++17 std::void_t):

tempate<typename Sorter>
struct wrapper:
Sorter
{
#ifdef __clang__
using Sorter::operator();

template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<false, std::void_t<Iterable>>
{}
#endif
};

template<typename Sorter>
struct sorter_facade
{
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<
not has_sort<wrapper<Sorter>, Iterable>,
decltype(std::declval<Sorter&>()(std::begin(iterable), std::end(iterable)))
>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};

我猜它在 g++ 和 clang++ 中滥用了不同的特定于编译器的行为,并实现了一些本不应该工作的东西,但仍然......我很惊讶它的工作,即使在我的整个项目中,它有还有更多棘手的事情要处理...

最佳答案

我很确定这是 clang 中的一个错误。 sorter_facade<Sorter>::operator() 的返回类型取决于模板参数 Iterator。不过,编译器似乎在知道参数之前就决定将 SFINAE 淘汰。

但无论是否有错误,您都可以通过显式推迟返回类型的计算来解决这个问题。这是一个不依赖黑魔法的版本。适用于 gcc-5.2 和 clang-3.6:

template<typename Sorter, typename Iterable>
struct sort_result
{
using type = decltype(
std::declval<Sorter&>()(
std::begin(std::declval<Iterable&>()),
std::end(std::declval<Iterable&>())));
};

template<typename Sorter, typename Deferred>
using sort_result_t = typename sort_result<Sorter, Deferred>::type;

template<typename Sorter>
struct sorter_facade
{
template <typename Iterable>
auto operator()(Iterable& iterable) const
-> sort_result_t<Sorter, Iterable>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};

struct heap_sorter:
sorter_facade<heap_sorter>
{
using sorter_facade<heap_sorter>::operator();

template<typename Iterator>
auto operator()(Iterator first, Iterator last) const
-> void
{
std::make_heap(first, last);
std::sort_heap(first, last);
}
};

int main()
{
std::vector<int> vec(3);
heap_sorter{}(vec);
}

诀窍是:编译器不知道您稍后是否特化了 result_type。因此,它必须等到您实际使用它时,才会尝试确定返回类型。

关于c++ - CRTP 类中成员函数的可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33657908/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com