C+的问题+;用于检测函数是否存在的元函数 我有一个问题,我不理解C++元函数。我正在使用C++14编译苹果的Clang8.1.0版本。下面是说明问题的工作代码
我从其他地方抄袭了一个元函数,我正在尝试使用它。它旨在检测名为“bananify”的函数,这些函数具有传递给元函数的类型的参数。你称之为C+的问题+;用于检测函数是否存在的元函数 我有一个问题,我不理解C++元函数。我正在使用C++14编译苹果的Clang8.1.0版本。下面是说明问题的工作代码,c++,c++14,metaprogramming,template-meta-programming,C++,C++14,Metaprogramming,Template Meta Programming,我从其他地方抄袭了一个元函数,我正在尝试使用它。它旨在检测名为“bananify”的函数,这些函数具有传递给元函数的类型的参数。你称之为 BananifyDetector<int>::value 问题是,它只在被搜索的函数在BananifyFinder的模板定义之前声明时才起作用,而不是它的实例化。因此,在我的示例代码中,我希望这两个 BananifyFinder<int> BananifyFinder<std::string> BananifyFin
BananifyDetector<int>::value
问题是,它只在被搜索的函数在BananifyFinder的模板定义之前声明时才起作用,而不是它的实例化。因此,在我的示例代码中,我希望这两个
BananifyFinder<int>
BananifyFinder<std::string>
BananifyFinder
BananifyFinder
成功地使用下面的代码,但由于定义了bananify(std::string)的位置,它失败了
这是令人沮丧的,就像我把函数检测器放在头文件中一样,我必须在客户机代码中包含顺序感知,这是一个巨大的痛苦,在某些情况下可能不可能正确
我不知道这里发生了什么。它是C++的特性,还是一个笨拙的bug?还是我做的蠢事?
谢谢你的帮助
#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> ");
}
#包括
#包括
////////////////////////////////////////////////////////////////////////////////
//要检测的bananify函数
//这已成功找到。
双bananify(int)
{
返回0.0;
}
///一种元函数,用于检测名为“bananify”的单参数函数
///exists with接受传递给元函数的类型的参数。
///
///请注意,自动强制转换有时会妨碍功能的正常运行
///如果存在BananifyFinder::值,BananifyFinder::值将返回true。
模板
类BananifyFinder{
私人:
使用void的模板t=void;
模板
结构测试:std::false\u类型
{
类型定义无效返回类型;
};
模板
结构测试:std::true\u类型
{
typedef decltype(bananify(std::declval())returnType;
};
公众:
typedef typename测试\::returnType returnType;
constexpr静态布尔值=测试值;
};
////////////////////////////////////////////////////////////////////////////////
//要检测的bananify函数,它接受std::strings
//这无法找到,但如果我们在BananifyFinder声明之前移动它
//将被发现;
std::string bananify(std::string)
{
返回“s”;
}
//找不到bananify函数的伪类
类Nothing{};
//检查元函数“T”的结果
模板
void CheckBanana(const std::string和str)
{
使用DetectedType=BananifyFinder;
std::cout模板分两个阶段进行解析
在第一种方法中,解析独立于模板参数的表达式。在第二种方法中,解析与模板相关的参数依赖项
decltype(bananify(std::declval
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
}
#包括
#包括
#包括
甲级{
公众:
双bananify(int)
{
返回0.0;
}
};
//查找bananify(ARG1)作为C的成员:
模板
类BananifyFinder{
私人:
使用void的模板t=void;
模板
结构测试:std::false\u类型
{
类型定义无效返回类型;
};
模板
结构测试:std::true\u类型
{
typedef decltype(std::declval().bananify(std::declval())returnType;
};
公众:
typedef typename测试\::returnType returnType;
constexpr静态布尔值=测试值;
};
B类{
公众:
std::string bananify(std::string)
{
返回“s”;
}
};
//检查元函数“T”的结果
模板
void CheckBanana(const std::string和str)
{
使用DetectedType=BananifyFinder;
std::cout其他人留下了答案,但似乎已被删除。这是一个与模板名称相关的查找问题
地址在这里
这里的更多细节为了正确起见,banify(std::string)
需要声明(而不是定义)在检测到模板BananifyFiner
之前。在使用#include
之前,您是否希望能够使用std::vector
?这就是这里发生的事情。AndyG,这更像是在使用MyClass之前必须声明MyClass。@brunobignose:不完全是……我想我需要写一个答案。a与姓名相关的查找问题。我在编辑时“暂停”了我的查找以澄清问题。我在编辑时“暂停”了查找以澄清问题。
#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
}