用于检测函数是否存在的C++元函数的问题
Issues with a C++ metafunction to detect if a function exists
我有一个不理解的C++元函数的问题。我正在使用 C++14 编译 Apple 的 clang 8.1.0 版本。说明该问题的工作代码如下。
我已经从其他地方抄了一个元函数,我正在尝试使用它。它旨在检测名为"bananify"的函数,这些函数具有传递给元函数的类型参数。你称之为...
BananifyDetector<int>::value
如果它可以看到表单的声明函数,则应该返回 true...
bananify(int)
问题在于,只有当正在搜索的函数是在BananifyFinder的模板定义之前声明的,而不是实例化它时,它才有效。所以在我的示例代码中,我本来期望两者,
BananifyFinder<int>
BananifyFinder<std::string>
我下面的代码成功了,但由于定义了bananify(std::string(的位置,它失败了。
这很令人沮丧,因为如果我将函数检测器放在头文件中,我必须在客户端代码中包含顺序感知,这是一个深刻的痛苦,在某些情况下可能不可能正确处理。
我不确定这里发生了什么。这是一个C++功能,一个叮当中的错误还是我做过的事情?
任何帮助表示赞赏。
#include <iostream>
#include <type_traits>
////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected
// This is successfully found.
double bananify(int)
{
return 0.0;
}
/// A meta function that detects if a single argument function named 'bananify'
/// exists with takes an argument of the type passed to the metafunction.
///
/// Note, automatic casts will get in the way occasionally so if function
/// bananify(float) exists, a BananifyFinder<int>::value will return true.
template<class ARG1>
class BananifyFinder {
private :
template<typename ...> using VoidT_ = void;
template<typename A1, typename = void>
struct Test_ : std::false_type
{
typedef void returnType;
};
template<typename A1>
struct Test_<A1, VoidT_<decltype(bananify(std::declval<A1>()))>> : std::true_type
{
typedef decltype(bananify(std::declval<A1>())) returnType;
};
public :
typedef typename Test_<ARG1>::returnType returnType;
constexpr static bool value = Test_<ARG1>::value;
};
////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected that takes std::strings
// This fails to be found, but if we move it before the declaration of BananifyFinder it
// will be found;
std::string bananify(std::string)
{
return "s";
}
// dummy class with no bananify function to be found
class Nothing{};
// check the results of the metafunction 'T'
template<class T>
void CheckBanana(const std::string &str)
{
using DetectedType = BananifyFinder<T>;
std::cout << str << " detected is " << DetectedType::value << std::endl;
std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
// this should print "BananifyFinder<int> 1 d"
CheckBanana<int>("BananifyFinder<int> ");
// this should print "BananifyFinder<std::string> 1 NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"
// but it prints "BananifyFinder<std::string> 0 v"
// FAILS
CheckBanana<std::string>("BananifyFinder<std::string> ");
// this should print "BananifyFinder<Nothing> 0 v"
CheckBanana<Nothing>("BananifyFinder<Nothing> ");
}
模板分两个阶段解析。
在第一个中,解析独立于模板参数的表达式。在第二个中,在执行参数依赖查找的位置解析模板依赖参数依赖
。decltype(bananify(std::declval<A1>()))>
是参数依赖构造(取决于A1
(。
从此页面
ADL 检查具有外部链接的函数声明,这些声明是 从模板定义上下文和模板中可见 实例化上下文(换句话说,添加新函数 模板定义后的声明不使其可见,除非 通过ADL(。
因此,您的代码会查看std::
(使用 ADL(,但找不到bananify
函数。
在模板实例化之前移动它足以使其有资格进行查找。
我相信bananify
引用在实例化之前在模板中解析,因为它不依赖。因此,看不到未声明的覆盖。
通常,您希望搜索可用作类型成员的函数,而不是在顶层,在这种情况下,问题就消失了:
#include <iostream>
#include <type_traits>
#include <typeinfo>
class A {
public:
double bananify(int)
{
return 0.0;
}
};
// Find bananify(ARG1) as a member of C:
template<class C, class ARG1>
class BananifyFinder {
private :
template<typename ...> using VoidT_ = void;
template<typename A1, typename = void>
struct Test_ : std::false_type
{
typedef void returnType;
};
template<typename A1>
struct Test_<A1, VoidT_<decltype(std::declval<C>().bananify(std::declval<A1>()))>> : std::true_type
{
typedef decltype(std::declval<C>().bananify(std::declval<A1>())) returnType;
};
public :
typedef typename Test_<ARG1>::returnType returnType;
constexpr static bool value = Test_<ARG1>::value;
};
class B {
public:
std::string bananify(std::string)
{
return "s";
}
};
// check the results of the metafunction 'T'
template<class C, class T>
void CheckBanana(const std::string &str)
{
using DetectedType = BananifyFinder<C,T>;
std::cout << str << " detected is " << DetectedType::value << std::endl;
std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}
int main(int argc, char *argv[])
{
CheckBanana<A,int>("BananifyFinder<int> "); // ok
CheckBanana<B,std::string>("BananifyFinder<std::string> "); // ok
}
其他人留下了答案,但似乎已被删除。这是模板的名称相关查找问题。
此处解决 C++模板中的名称查找
以及更多细节 这里 http://en.cppreference.com/w/cpp/language/adl
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗