- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
过去几个小时我一直在努力解决一个非常奇怪的问题(在用 SFINAE 解决了 5-6 个其他问题之后,因为我是新手)。基本上在下面的代码中,我想让 f()
为所有可能的模板实例化工作,但是 g()
仅在 N == 2
:
#include <type_traits>
#include <iostream>
template<typename T, int N>
class A
{
public:
void f(void);
void g(void);
};
template<typename T, int N>
inline void A<T, N>::f()
{
std::cout << "f()\n";
}
template<typename T, int N, typename std::enable_if<N == 2, void>::type* = nullptr>
inline void A<T, N>::g()
{
std::cout << "g()\n";
}
int main(int argc, char *argv[])
{
A<float, 2> obj;
obj.f();
obj.g();
return 0;
}
当我尝试编译它时,我收到一个关于有 3 个而不是两个模板参数的错误。然后,经过一些试验,我决定将 g()
的定义移动到 A
本身的定义中,如下所示:
#include <type_traits>
#include <iostream>
template<typename T, int N>
class A
{
public:
void f(void);
template<typename t = T, int n = N, typename std::enable_if<N == 2, void>::type* = nullptr>
void g()
{
std::cout << "g()\n";
}
};
template<typename T, int N>
inline void A<T, N>::f()
{
std::cout << "f()\n";
}
int main(int argc, char *argv[])
{
A<float, 2> obj;
obj.f();
obj.g();
return 0;
}
现在,奇迹般地一切正常。但我的问题是为什么?编译器没有看到在类定义中我试图内联一个也依赖于 3 个模板参数的成员函数吗?或者让我们反过来问:如果它在 A
的定义内有效,为什么它在外部不起作用?哪里不一样?不是还有 3 个参数,这比类 A
需要的模板参数多 +1 吗?
另外,为什么它只在我将第三个参数设为非类型参数而不是类型参数时才起作用?请注意,我实际上创建了一个由 enable_if 返回的类型的指针,并为其分配了一个默认值 nullptr,但我发现我不能像我在这里看到的其他 SO 论坛帖子那样将它作为类型参数留在那里。
非常感谢,谢谢!!!
最佳答案
那是因为模板化类中的模板化函数有两组 模板参数集,而不是一组。因此,“正确”的形式是:
template<typename T, int N>
class A
{
public:
void f(void);
template<typename std::enable_if<N == 2, void>::type* = nullptr>
void g(void);
};
template<typename T, int N> // Class template.
template<typename std::enable_if<N == 2, void>::type* /* = nullptr */> // Function template.
inline void A<T, N>::g()
{
std::cout << "g()\n";
}
查看实际效果 here .
[请注意,这不是实际上正确的,原因在此答案的底部进行了解释。如果 N != 2
就会坏掉.]
如果您愿意,请继续阅读以获取解释。
还在我身边吗?好的。让我们检查每种情况,好吗?
定义 A<T, N>::g()
外面A
:
template<typename T, int N>
class A
{
public:
void f(void);
void g(void);
};
template<typename T, int N, typename std::enable_if<N == 2, void>::type* = nullptr>
inline void A<T, N>::g()
{
std::cout << "g()\n";
}
在这种情况下,A<T, N>::g()
的模板声明与 A
不匹配的模板声明。因此,编译器会发出错误。此外,g()
本身不是模板化的,所以模板不能在不改变的情况下拆分为类模板和函数模板 A
的定义。
template<typename T, int N>
class A
{
public:
void f(void);
// Here...
template<typename std::enable_if<N == 2, void>::type* = nullptr>
void g(void);
};
// And here.
template<typename T, int N> // Class template.
template<typename std::enable_if<N == 2, void>::type* /* = nullptr */> // Function template.
inline void A<T, N>::g()
{
std::cout << "g()\n";
}
定义 A<T, N>::g()
里面A
:
template<typename T, int N>
class A
{
public:
void f(void);
template<typename t = T, int n = N, typename std::enable_if<N == 2, void>::type* = nullptr>
void g()
{
std::cout << "g()\n";
}
};
在这种情况下,由于 g()
是内联定义的,它隐式具有 A
的模板参数,无需手动指定。因此,g()
实际上是:
// ...
template<typename T, int N>
template<typename t = T, int n = N, typename std::enable_if<N == 2, void>::type* = nullptr>
void g()
{
std::cout << "g()\n";
}
// ...
在这两种情况下,对于 g()
要拥有自己的模板参数,同时作为模板类的成员,函数模板参数必须与类模板参数分开。否则,函数的类模板将与类不匹配。
既然我们已经介绍过了,我应该指出 SFINAE 只关注立即模板参数。所以,对于 g()
将 SFINAE 与 N
一起使用, N
需要是它的模板参数;否则,如果您尝试调用,例如 A<float, 3>{}.g()
,您将收到错误消息.如有必要,这可以通过中介来完成。
此外,您需要提供 g()
的版本当 N != 2
时可以调用.这是因为 SFINAE 仅在至少存在一个有效版本的函数时才适用;如果没有 g()
的版本可以调用,然后将发出错误并且不会执行 SFINAE。
template<typename T, int N>
class A
{
public:
void f(void);
// Note the use of "MyN".
template<int MyN = N, typename std::enable_if<MyN == 2, void>::type* = nullptr>
void g(void);
// Note the "fail condition" overload.
template<int MyN = N, typename std::enable_if<MyN != 2, void>::type* = nullptr>
void g(void);
};
template<typename T, int N>
template<int MyN /*= N*/, typename std::enable_if<MyN == 2, void>::type* /* = nullptr */>
inline void A<T, N>::g()
{
std::cout << "g()\n";
}
template<typename T, int N>
template<int MyN /*= N*/, typename std::enable_if<MyN != 2, void>::type* /* = nullptr */>
inline void A<T, N>::g()
{
std::cout << "()g\n";
}
如果这样做,我们可以通过让中介来完成繁重的工作来进一步简化事情。
template<typename T, int N>
class A
{
public:
void f(void);
template<bool B = (N == 2), typename std::enable_if<B, void>::type* = nullptr>
void g(void);
template<bool B = (N == 2), typename std::enable_if<!B, void>::type* = nullptr>
void g(void);
};
// ...
查看实际效果 here .
关于c++ - 为什么 SFINAE (enable_if) 从类定义内部工作而不是从外部工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904099/
我正在使用这样的模板别名: template ::value>::type> using vec2 = std::pair; template ::value>::type> using vec3 =
基本问题陈述 我正在学习 SFINAE。我尝试了一个非常简单的 enable_if : // 1: A foo() that accepts arguments that are derived fr
在language reference of std::enable_if at cppreference包括以下注释 Notes A common mistake is to declare two
我对 SFINAE 有基本的了解,我想我理解了很多关于如何 std::enable_if 的例子。利用它来选择函数模板特化,但我很难理解它如何用于类模板。 以下例子来自cppreference.com
这有什么问题? 我认为这应该在使用 enable if 时起作用??? 帮助?? 不应该排除第二个构造函数吗? #include #include #include template class
我试图在模板类中声明函数,以便函数声明依赖于模板类型参数。 template struct Block { static bool parse(int32_t index,
我正在尝试一种基于类模板参数来专门化成员函数的方法,而不必在类上使用 SFINAE(并导致代码重复或创建另一个类)。 由于两个模板参数不能是可选的,并且参数 enable_if 在指南中是不受欢迎的,
我遇到一个问题,未知代码正在使用试图在编译时和运行时取消引用类型的元模板。这意味着,它们遍历指针层次结构直到找到匹配器。 现在通常这很好用。但是当用户传递类似的东西时: typedef struct
我试图了解 std::enable_if 是如何工作的 inn 模板参数。 #include #include #include using namespace std; class Inter
有谁知道为什么下面的代码可以编译 static const size_t CONSTANT = /* ... */; template = 0 > res_type foo() { // ...
我有一个类定义为: template class AdjacencyList; 其中 V 和 E 分别是顶点和边值的类型。 我目前正在尝试在 AdjacencyList 中定义以下成员函数: std
我有以下代码无法在 VC2010 上编译: #include using namespace std; template typename enable_if::type foo() { retu
为什么编译器对 std::tuple 的访问者具有以下定义顺序很重要 namespace TupleVisit{ //This function SHOULD BE DEFINED S
我想使用 type_traits 是否通过 shared_ptr 重载。 struct A { A(int i) : x(i) {} int x; }; int main() {
作为一个实验,我试图使一个没有参数的 void 成员函数根据类模板参数改变行为: #include #include template class MyClass { public: void
我正在使用 enable_if 语句来删除考虑中的可能方法。 #include "gmpxx.h" #include template struct is_ring_field { }; temp
是否有任何“更干净”的方式(我的意思是减少重复代码)来编写以下内容? template class Test { struct Foo1 { int a; }; struct F
在C ++中,请考虑以下示例: template struct q; template struct q { q() { cout struct q {
我对 std::enable_if 很陌生,想知道如何使用它。我有一个模板类: template class foo { } 现在我只想在 a + b 等于 10 时实例化它。我可以使用 std::e
我最近遇到了一个有趣的 enable_if 用法版本,它用于有条件地启用具有更好可读性的函数,因为该函数的返回类型不是 enable_if 的一部分(请参阅 cleaner_usage): #incl
我是一名优秀的程序员,十分优秀!