模板参数推导和 SFINAE - 使用 std::enable_if
Template argument deduction and SFINAE - using std::enable_if
我正在研究如何过滤传递给重载函数模板的类型。我正在使用 Visual Studio 2013。
三部分问题:
- 为什么我的编译器不能推断出
Blorg3
?
TFoo2(argc)
产生编译错误的原因和#1一样吗?
- 有没有办法将模板参数传递给构造函数?
示例代码如下:
#include <type_traits>
#define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type
#define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type
template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; }
template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; }
template <class T> IFINT(T, int) Blorg2(T n) { return n + 1; }
template <class T> IFPTR(T, int) Blorg2(T n) { return *n + 1; }
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
struct TFoo1 {
template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { }
};
struct TFoo2 {
template <class T> TFoo2(IFINT(T, T) n) { }
};
int main(int argc, char* argv[])
{
Blorg1(argc); // intellisense not happy
Blorg2(argc);
Blorg3<int>(argc); // why cant deduce?
Blorg1(*argv); // intellisense not happy
Blorg2(*argv);
Blorg3<char*>(*argv); // why cant deduce?
(void)TFoo1(argc); // intellisense not happy
(void)TFoo2(argc); // intellisense not happy and !!wont compile!!
return 0;
}
Why cant my compiler deduce Blorg3?
在 std::enable_if<std::is_pointer<T>::value, R>::type
中,::type
指的是依赖于模板参数 T
和 R
的嵌套名称。这是一个非推导上下文 (§14.8.2.5/5),因此编译器不会推导模板参数。
Is that why TFoo2(argc) generates a compiler error?
是的,构造函数模板必须能够推导出其模板参数,在这种情况下它不能。
Is there a syntax to provide template parameters to a constructor?
不,正如我已经提到的,你不能明确地这样做,它们必须被推导,或者模板参数必须有默认参数。
回答 1/2 关于 SFINAE 不工作的原因:
SFINAE 和 模板参数推导 在这种情况下不能很好地协同工作。
或者,只要您知道事情发生的正确顺序,它们就会这样做。
推导必须保证有效才能被视为在此实例中调用的可能函数。
这里有一种不太技术性的方式来看待这个问题:
编译器会搜索与您尝试调用的函数匹配的可能函数签名。 [see overload resolution]
如果它找到一个模板参数,它会查看它是否对推导有效。
这就是您 运行 遇到问题的原因。这两个事件发生的顺序是 SFINAE 对 Blorg1
、Blorg2
和 TFoo1
但对 Blorg3
或 TFoo2
.
起作用的原因
使用 Blorg3
和 TFoo2
时,编译器无法插入您传递给模板类型的参数,因为它会创建无法解析的循环依赖关系。
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
Blorg3<char*>(*argv); // why cant deduce?
要解决 Blorg3
中的 SFINAE,需要了解 T
。然而,T
在 SFINAE 解决之前是未知的。
为什么 TFoo2
不起作用。
第 3 部分 - 关于模板和构造函数
是的,您可以将模板参数传递给构造函数,但前提是您通过推导来完成,例如 TFoo1
.
您不能显式将模板参数传递给构造函数。
我正在研究如何过滤传递给重载函数模板的类型。我正在使用 Visual Studio 2013。
三部分问题:
- 为什么我的编译器不能推断出
Blorg3
? TFoo2(argc)
产生编译错误的原因和#1一样吗?- 有没有办法将模板参数传递给构造函数?
示例代码如下:
#include <type_traits>
#define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type
#define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type
template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; }
template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; }
template <class T> IFINT(T, int) Blorg2(T n) { return n + 1; }
template <class T> IFPTR(T, int) Blorg2(T n) { return *n + 1; }
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
struct TFoo1 {
template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { }
};
struct TFoo2 {
template <class T> TFoo2(IFINT(T, T) n) { }
};
int main(int argc, char* argv[])
{
Blorg1(argc); // intellisense not happy
Blorg2(argc);
Blorg3<int>(argc); // why cant deduce?
Blorg1(*argv); // intellisense not happy
Blorg2(*argv);
Blorg3<char*>(*argv); // why cant deduce?
(void)TFoo1(argc); // intellisense not happy
(void)TFoo2(argc); // intellisense not happy and !!wont compile!!
return 0;
}
Why cant my compiler deduce Blorg3?
在 std::enable_if<std::is_pointer<T>::value, R>::type
中,::type
指的是依赖于模板参数 T
和 R
的嵌套名称。这是一个非推导上下文 (§14.8.2.5/5),因此编译器不会推导模板参数。
Is that why TFoo2(argc) generates a compiler error?
是的,构造函数模板必须能够推导出其模板参数,在这种情况下它不能。
Is there a syntax to provide template parameters to a constructor?
不,正如我已经提到的,你不能明确地这样做,它们必须被推导,或者模板参数必须有默认参数。
回答 1/2 关于 SFINAE 不工作的原因:
SFINAE 和 模板参数推导 在这种情况下不能很好地协同工作。
或者,只要您知道事情发生的正确顺序,它们就会这样做。
推导必须保证有效才能被视为在此实例中调用的可能函数。
这里有一种不太技术性的方式来看待这个问题:
编译器会搜索与您尝试调用的函数匹配的可能函数签名。 [see overload resolution]
如果它找到一个模板参数,它会查看它是否对推导有效。
这就是您 运行 遇到问题的原因。这两个事件发生的顺序是 SFINAE 对 Blorg1
、Blorg2
和 TFoo1
但对 Blorg3
或 TFoo2
.
使用 Blorg3
和 TFoo2
时,编译器无法插入您传递给模板类型的参数,因为它会创建无法解析的循环依赖关系。
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
Blorg3<char*>(*argv); // why cant deduce?
要解决 Blorg3
中的 SFINAE,需要了解 T
。然而,T
在 SFINAE 解决之前是未知的。
为什么 TFoo2
不起作用。
第 3 部分 - 关于模板和构造函数
是的,您可以将模板参数传递给构造函数,但前提是您通过推导来完成,例如 TFoo1
.
您不能显式将模板参数传递给构造函数。