提问人:Yves 提问时间:7/1/2023 最后编辑:Yves 更新时间:7/2/2023 访问量:89
为什么我在使用 std::enable_if [duplicate] 时出现过载错误
Why do I get overload error while using std::enable_if [duplicate]
问:
我想根据类的一个模板参数定义两种成员函数。这是我的代码:run
template <int VAL, typename D = std::chrono::seconds, bool IS_DAILY = false>
class TimerJob {
public:
template <typename C, typename F, typename... Args, typename = std::enable_if_t<IS_DAILY>>
void run(F C::*f, C* c, Args&&... args) {
td_ = std::make_unique<std::thread>(
[](F C::*f, C* c, Args... args){
do {
c.f(args...);
std::this_thread::sleep_for(D{VAL});
} while (true);
});
}
template <typename C, typename F, typename... Args, typename = std::enable_if_t<!IS_DAILY>>
void run(F C::*f, C* c, Args&&... args) {
td_ = std::make_unique<std::thread>(
[](F C::*f, C* c, Args... args){
do {
c.f(args...);
// just an example to make a difference with the other run()
// the real case is much complicated
std::this_thread::sleep_for(D{VAL + 60});
} while (true);
});
}
private:
std::unique_ptr<std::thread> td_;
};
如您所见,我正在尝试用不同的 .run
IS_DAILY
但是我得到了一个错误:
<source>:27:8: error: 'template<int VAL, class D, bool IS_DAILY> template<class C, class F, class ... Args, class> void TimerJob<VAL, D, IS_DAILY>::run(F C::*, C*, Args&& ...)' cannot be overloaded with 'template<int VAL, class D, bool IS_DAILY> template<class C, class F, class ... Args, class> void TimerJob<VAL, D, IS_DAILY>::run(F C::*, C*, Args&& ...)'
27 | void run(F C::*f, C* c, Args&&... args) {
| ^~~
<source>:15:8: note: previous declaration 'template<int VAL, class D, bool IS_DAILY> template<class C, class F, class ... Args, class> void TimerJob<VAL, D, IS_DAILY>::run(F C::*, C*, Args&& ...)'
15 | void run(F C::*f, C* c, Args&&... args) {
我现在很困惑......不是这样用的吗?std::enable_if
顺便说一句,我正在使用 C++14。
答:
3赞
alfC
7/1/2023
#1
因为(模板)签名完全相同。
一种常见的解决方法是使用非类型参数来解决此问题。 在任何情况下,您始终需要使 enable_if 的内容依赖于至少一个当前参数。
试试这个:
template <typename C, typename F, typename... Args, std::enable_if_t<IS_DAILY and sizeof(C*)>* =nullptr> // typename = std::enable_if_t<IS_DAILY>>
...
}
template <typename C, typename F, typename... Args, std::enable_if_t<!IS_DAILY and sizeof(C*)>* =nullptr> // typename = std::enable_if_t<!IS_DAILY>>
void run(F C::*f, C* c, Args&&... args) {
...
}
我认为这就是它的工作原理。
代码对比:https://godbolt.org/z/b5v13MaWf(取消注释两行末尾的代码,查看原始问题)
注意:在 C++ 14 中,缺少 ,您应该为此使用标记调度,而不是 。像这样:https://godbolt.org/z/KhW76Wbszif constexpr
std::enable_if
评论
1赞
Yves
7/1/2023
嗯,但会产生另一个错误:TimerJob<30, std::chrono::seconds, false> job;
error: no type named 'type' in 'struct std::enable_if<false, void>' 2610 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
0赞
alfC
7/1/2023
真?godbolt.org/z/WMe71GnbK
0赞
Patrick Roberts
7/1/2023
@alfC真的。godbolt.org/z/q5dh1K5W3
0赞
alfC
7/1/2023
我明白你的意思了,在这种情况下,你需要做一个额外的步骤:godbolt.org/z/b5v13MaWf
1赞
alfC
7/1/2023
的参数 always 必须是依赖于前面模板参数的表达式。这是使其正常工作的唯一方法(否则它会产生硬错误,而不是 SFINAE)。要使表达式依赖于当前模板参数,我必须添加一个不影响结果的虚假依赖项,因为始终为 true,我可以添加 .我通过Raymond Chen的推荐来进一步确保这一点,因为将来我们可能会有零大小的类,但永远不会有指针。我仍然建议使用标签调度enable_if
sizeof(anything)
and true
-2赞
MURUGESAN N
7/1/2023
#2
我尝试使用您的代码作为基本版本:
/*
Compilation using MINGW at Windows:
/usr/bin/g++.exe -g -c -Wall 76593060.cpp -std=c++17
$ /usr/bin/ls -ltr 76593060.o
-rw----r--+ 1 murugesan openssl 19360 Jul 1 09:02 76593060.o
*/
#include <thread> // ‘std::thread’ is defined in header ‘<thread>’;
#include <memory> // ‘std::unique_ptr’ is defined in header ‘<memory>’
#include <type_traits> // std::enable_if_t
#include <chrono> // std::chrono::seconds
#include <iostream>
using namespace std; // Remove all std::
template <int VAL, typename D = chrono::seconds, bool IS_DAILY = false>
class TimerJob
{
public:
template <typename C, typename F, typename... Args, typename = enable_if_t<IS_DAILY>>
void run(F C::*f, C* c, Args&&... args)
{
td_ = make_unique<thread>(
[](F C::*f, C* c, Args... args){
do
{
c.f(args...);
this_thread::sleep_for(D{VAL});
} while (true);
});
}
// REQUIREMENT VIEWED AT ERROR DURING COMPILATION:
// template<class C, class F, class ... Args, class>
// HOWEVER OLD CODE WAS NOT HAVING FOURTH ARGUMENT:
template <typename C, typename F, typename... Args, typename = enable_if_t<!IS_DAILY>>
// void run(F C::*f, C* c, Args&&... args)
void run(F C::*f, C* c, Args&&... args, bool DAILY_VALIDATION)
{
td_ = make_unique<thread>(
[](F C::*f, C* c, Args... args){
do
{
c.f(args...);
// just an example to make a difference with the other run()
// the real case is much complicated
this_thread::sleep_for(D{VAL + 60});
} while (true);
});
}
private:
unique_ptr<thread> td_;
};
评论
TimerJob
IS_DAILY
run
if constexpr
requires IS_DAILY
requires (!IS_DAILY)
std::enable_if_t
template <typename C, typename F, typename... Args, bool IS_DAILY_FUNC = IS_DAILY, typename = std::enable_if_t<IS_DAILY_FUNC>>
IS_DAILY_FUNC
std::enable_if