正在检查是否存在接受T参数的非成员函数
Checking if non-member function that accepts T param exists
我想检查是否存在接受T参数类型的非成员函数。为了做到这一点,我使用了Walter E.Brown先生在cppcon上提出的void_t
"技巧"(同样的技巧可以毫无问题地检查成员类型或成员函数是否存在)。
#include <iostream>
#include <type_traits>
template<typename...>
using void_t = void;
void Serialize(float&)
{
}
template<typename T, typename = void>
struct has_external_serialize : std::false_type
{
};
template<typename T>
struct has_external_serialize<T, void_t<decltype(Serialize(std::declval<T&>()))>> : std::true_type
{
};
void Serialize(int&)
{
}
int main(int argc, const char * argv[])
{
std::cout<<has_external_serialize<float>::value<<has_external_serialize<int>::value;
}
当使用GCC编译时,此代码打印11
,当使用clang(xcode 5.1.1)编译时,打印10
。
我的问题是——这个代码正确吗?如果是,clang或GCC中是否存在错误,或者代码位于某个"实现定义"区域,我不能假设它在所有平台上都会有相同的行为?
编译器之间的差异是由void_t
的定义引起的:我实现的Is_complete类型特征是否暴露了编译器错误?简而言之,该标准不清楚别名模板专门化中未使用的参数是否会导致替换失败或被忽略。《化学武器公约》第1558号问题的决议阐明,该问题中void_t
的较短定义应该有效。
使用解决该问题
template<typename... Ts>
struct make_void { typedef void type;};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
两个编译器都产生CCD_ 6。
§14.6.4.2[临时部门日期]:
对于依赖于模板参数的函数调用使用通常的查找规则(3.4.1,3.4.2、3.4.3),但除外
- 对于使用非限定名称查找(3.4.1)或限定名称查找的查找部分找到模板定义上下文
- 对于使用关联名称空间的查找部分(3.4.2),只有在模板定义上下文中找到的函数声明或者找到模板实例化上下文
如果函数名是不合格的id,则调用将为格式错误,或者如果在关联的命名空间考虑了具有在所有翻译中在这些名称空间中引入的外部链接单位,而不仅仅是考虑模板中的声明定义和模板实例化上下文,则程序具有未定义的行为。
Serialize
的不合格查找是在模板定义上下文中执行的,不会找到Serialize(int &)
,并且类型为int&
的参数没有ADL,因此10
是正确的输出。
相关文章:
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 使用指向成员的指针将成员函数作为参数传递
- 如何将lambda作为模板类的成员函数参数
- 将成员函数指针作为参数传递给模板方法
- c++构造函数成员初始化:传递参数
- 使用带有 ref 参数的成员函数创建线程时出现编译错误
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 模板化检查是否存在带有参数列表的类成员函数?
- 如何将类成员方法的参数列表自动填充写入可变参数?
- 为什么我需要在成员发起器列表中重复基类的模板参数?
- C++向量默认为成员参数
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- 可变参数模板参数扩展 类型为 std::function 的类成员
- 绑定到可变参数成员函数
- C/C++ 包含点的宏参数(成员访问运算符)
- 将const char * const参数成员分配给新值
- 基于模板参数成员函数参数的模板专用化
- 如何访问可变参数成员
- 可变类参数成员变量的异构存储
- 非模板类中的可变参数成员