SFINAE:"enable_if cannot be used to disable this declaration"
SFINAE: "enable_if cannot be used to disable this declaration"
为什么我不能在以下上下文中使用enable_if
?
我想检测我的模板化对象是否具有成员函数notify_exit
template <typename Queue>
class MyQueue
{
public:
auto notify_exit() -> typename std::enable_if<
has_member_function_notify_exit<Queue, void>::value,
void
>::type;
Queue queue_a;
};
初始化方式:
MyQueue<std::queue<int>> queue_a;
我不断得到(叮当6(:
example.cpp:33:17: error: failed requirement 'has_member_function_notify_exit<queue<int, deque<int, allocator<int> > >, void>::value';
'enable_if' cannot be used to disable this declaration
has_member_function_notify_exit<Queue, void>::value,
或 (g++ 5.4(:
In instantiation of 'class MyQueue<std::queue<int> >':
33:35: required from here
22:14: error: no type named 'type' in 'struct std::enable_if<false, void>'
我尝试了很多不同的东西,但不知道为什么我不能使用enable_if
来禁用此功能。 这不正是enable_if
的目的吗?
我在这里放了一个完整的例子(以及经常失败 cpp.sh 链接(
我在SO上发现了类似的Q/A,但通常这些问题更复杂,并尝试不同的东西。
当您实例化MyQueue<std::queue<int>>
模板参数时,std::queue<int>
被替换到类模板中。在成员函数声明中,导致使用不存在的typename std::enable_if<false, void>::type
。这是一个错误。不能使用不存在的类型声明函数。
enable_if
的正确用法必须取决于推导的模板参数。在模板参数推导期间,如果将推导的模板参数替换为模板参数失败(即"替换失败"(,那么您不会立即收到错误,它只会导致推导失败。如果扣除失败,则该函数不是重载解决的候选项(但仍会考虑任何其他重载(。
但是在您的情况下,在调用函数时不会推导模板参数,它是已知的,因为它来自周围的类模板。这意味着替换失败是一个错误,因为在你尝试执行重载解析来调用它之前,函数的声明格式不正确。
您可以通过将函数转换为函数模板来修复您的示例,因此它有一个必须推导的模板参数:
template<typename T = Queue>
auto notify_exit() -> typename std::enable_if<
has_member_function_notify_exit<T, void>::value,
void
>::type;
这里的enable_if
条件取决于T
而不是Queue
,所以::type
成员是否存在是未知的,直到你尝试用模板参数替换T
。函数模板有一个默认的模板参数,所以如果你只调用notify_exit()
而没有任何模板参数列表,它相当于notify_exit<Queue>()
,这意味着enable_if
条件取决于Queue
,正如你最初想要的那样。
此函数可能会被误用,因为调用方可能会notify_exit<SomeOtherType>()
调用它,以诱骗enable_if
条件,具体取决于错误的类型。如果调用者这样做,他们应该得到编译错误。
使代码工作的另一种方法是对整个类模板进行部分专用化,以便在不需要函数时简单地删除该函数:
template <typename Queue,
bool Notifiable
= has_member_function_notify_exit<Queue, void>::value>
class MyQueue
{
public:
void notify_exit();
Queue queue_a;
};
// partial specialization for queues without a notify_exit member:
template <typename Queue>
class MyQueue<Queue, false>
{
public:
Queue queue_a;
};
您可以避免以几种不同的方式重复整个类定义两次。您可以将所有公共代码提升到基类中,并且只在依赖于它的派生类中添加notify_exit()
成员。或者,您可以仅将条件部分移动到基类中,例如:
template <typename Queue,
bool Notifiable
= has_member_function_notify_exit<Queue, void>::value>
class MyQueueBase
{
public:
void notify_exit();
};
// partial specialization for queues without a notify_exit member:
template <typename Queue>
class MyQueueBase<Queue, false>
{ };
template<typename Queue>
class MyQueue : public MyQueueBase<Queue>
{
public:
// rest of the class ...
Queue queue_a;
};
template<typename Queue, bool Notifiable>
void MyQueueBase<Queue, Notifiable>::notify_exit()
{
static_cast<MyQueue<Queue>*>(this)->queue_a.notify_exit();
}
使用 C++20 和概念,您可以使用requires
:
void notify_exit() requires has_member_function_notify_exit<Queue, void>::value;
实例化模板会导致它包含的所有声明的成员实例化。此时,您提供的声明格式不正确。此外,SFINAE 在这里不适用,因为我们在实例化类模板时不会解决重载问题。
您需要将成员变成具有有效声明的内容,并确保检查延迟到重载解决。我们可以通过notify_exit
本身成为模板来做到这一点:
template<typename Q = Queue>
auto notify_exit() -> typename std::enable_if<
has_member_function_notify_exit<Q, void>::value,
void
>::type;
工作 cpp.sh 示例
- "error: no matching function for call to"构造函数错误
- 调用专用模板时出错"no matching function for call to [...]"
- C++ Singleton - Prevent ::instance() to variable
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- Visual Studio Code "undefined reference to `WinMain@16'"
- 使用 GCC 卸载的 OpenMP 卸载失败,并出现"Ptx assembly aborted due to errors"
- 如何解决"invalid conversion from 'char' to 'const char*'"
- 使用 MATLAB 编码器生成C++代码:编译错误"undefined reference to `rgb2gray_tbb_real64'"
- 尝试链接我的着色器时,我收到错误代码"error c5145 must write to gl_position"
- Python str to C++ to Python str
- 为什么创建友元类的实例会导致"undefined reference to"错误?
- System.InvalidCastException - SQL to C++ - safe_cast<float>
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- "no matching function for call to 'Vector::Vector'"错误
- vector<vector<double>> to mxArray using memcpy
- Tensorflow c++ api undefined reference to 'tflite::D efaultErrorReporter()'
- 当覆盖存在时调用基本虚拟"binded to object"函数
- SFINAE:"enable_if cannot be used to disable this declaration"
- Clang - 删除某些文件的"conversion function converting <A> to base class <B> will never be used"
- 为什么" 'static' may not be used when defining (as opposed to declaring) a static data member"?