是否可以编写模板来检查函数的存在?

是否可以编写模板来检查函数的存在?

是否可以编写一个模板来改变行为,具体取决于是否在类上定义了某个成员函数?

这是我想写的一个简单例子:

template<class T>std::string optionalToString(T* obj){
    if (FUNCTION_EXISTS(T->toString))
        return obj->toString();
    else
        return "toString not defined";}

所以,如果class T已经toString()确定的话,就使用它; 否则,它没有。我不知道怎么做的神奇部分是“FUNCTION_EXISTS”部分。


天涯尽头无女友
浏览 655回答 5
5回答

Smart猫小萌

是的,使用SFINAE,您可以检查给定的类是否提供某种方法。这是工作代码:#include&nbsp;<iostream>struct&nbsp;Hello{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;helloworld()&nbsp;{&nbsp;return&nbsp;0;&nbsp;}};struct&nbsp;Generic&nbsp;{};&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;SFINAE&nbsp;testtemplate&nbsp;<typename&nbsp;T>class&nbsp;has_helloworld{ &nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;char&nbsp;one; &nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;long&nbsp;two; &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;C>&nbsp;static&nbsp;one&nbsp;test(&nbsp;typeof(&C::helloworld)&nbsp;)&nbsp;; &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;C>&nbsp;static&nbsp;two&nbsp;test(...);&nbsp;&nbsp;&nbsp;&nbsp;public: &nbsp;&nbsp;&nbsp;&nbsp;enum&nbsp;{&nbsp;value&nbsp;=&nbsp;sizeof(test<T>(0))&nbsp;==&nbsp;sizeof(char)&nbsp;};};int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;*argv[]){ &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;<<&nbsp;has_helloworld<Hello>::value&nbsp;<<&nbsp;std::endl; &nbsp;&nbsp;&nbsp;&nbsp;std::cout&nbsp;<<&nbsp;has_helloworld<Generic>::value&nbsp;<<&nbsp;std::endl; &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;}我刚用Linux和gcc 4.1 / 4.3测试过它。我不知道它是否可以移植到运行不同编译器的其他平台

UYOU

这个问题很老,但是使用C ++ 11,我们有了一种新方法来检查函数是否存在(或者确实存在任何非类型成员),再次依赖SFINAE:template<class&nbsp;T>auto&nbsp;serialize_imp(std::ostream&&nbsp;os,&nbsp;T&nbsp;const&&nbsp;obj,&nbsp;int) &nbsp;&nbsp;&nbsp;&nbsp;->&nbsp;decltype(os&nbsp;<<&nbsp;obj,&nbsp;void()){ &nbsp;&nbsp;os&nbsp;<<&nbsp;obj;}template<class&nbsp;T>auto&nbsp;serialize_imp(std::ostream&&nbsp;os,&nbsp;T&nbsp;const&&nbsp;obj,&nbsp;long) &nbsp;&nbsp;&nbsp;&nbsp;->&nbsp;decltype(obj.stream(os),&nbsp;void()){ &nbsp;&nbsp;obj.stream(os);}template<class&nbsp;T>auto&nbsp;serialize(std::ostream&&nbsp;os,&nbsp;T&nbsp;const&&nbsp;obj) &nbsp;&nbsp;&nbsp;&nbsp;->&nbsp;decltype(serialize_imp(os,&nbsp;obj,&nbsp;0),&nbsp;void()){ &nbsp;&nbsp;serialize_imp(os,&nbsp;obj,&nbsp;0);}现在进行一些解释。首先,如果内部的第一个表达式无效(也就是说,函数不存在),我使用表达式SFINAEserialize(_imp)从重载解析中排除函数decltype。本void()是用来做的所有这些函数的返回类型void。如果两者都可用,则该0参数用于优先选择重载os << obj(文字0是类型的int,因此第一个重载是更好的匹配)。现在,您可能需要一个特征来检查函数是否存在。幸运的是,写起来很容易。但是请注意,您需要为自己想要的每个不同的函数名自己编写一个特征。#include&nbsp;<type_traits>template<class>struct&nbsp;sfinae_true&nbsp;:&nbsp;std::true_type{};namespace&nbsp;detail{ &nbsp;&nbsp;template<class&nbsp;T,&nbsp;class&nbsp;A0> &nbsp;&nbsp;static&nbsp;auto&nbsp;test_stream(int) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;->&nbsp;sfinae_true<decltype(std::declval<T>().stream(std::declval<A0>()))>; &nbsp;&nbsp;template<class,&nbsp;class&nbsp;A0> &nbsp;&nbsp;static&nbsp;auto&nbsp;test_stream(long)&nbsp;->&nbsp;std::false_type;}&nbsp;//&nbsp;detail::template<class&nbsp;T,&nbsp;class&nbsp;Arg>struct&nbsp;has_stream&nbsp;: &nbsp;&nbsp;&nbsp;decltype(detail::test_stream<T,&nbsp;Arg>(0)){};实例。并解释。首先,sfinae_true是一个帮助器类型,它基本上与写入相同decltype(void(std::declval<T>().stream(a0)), std::true_type{})。优点是它更短。接下来,取决于签入是否失败,struct has_stream : decltype(...)从任一端std::true_type或std::false_type最后继承。&nbsp;最后,为您提供所传递的任何类型的“值”,而无需您知道如何构建它。请注意,这只能在未评估的上下文中使用,例如,和其他。decltypetest_streamstd::declvaldecltypesizeof请注意,decltype不一定需要,因为sizeof(并且所有未评估的上下文)都获得了增强。它只是decltype已经提供了一种类型,因此只是更清洁。这是一个sizeof重载的版本:template<class&nbsp;T>void&nbsp;serialize_imp(std::ostream&&nbsp;os,&nbsp;T&nbsp;const&&nbsp;obj,&nbsp;int, &nbsp;&nbsp;&nbsp;&nbsp;int(*)[sizeof((os&nbsp;<<&nbsp;obj),0)]&nbsp;=&nbsp;0){ &nbsp;&nbsp;os&nbsp;<<&nbsp;obj;}由于同样的原因,int和long参数仍然存在。数组指针用于提供sizeof可以使用的上下文。

守着星空守着你

虽然这个问题已经有两年了,但我还是敢补充一下。希望它能澄清以前无可争议的优秀解决方案。我采用了Nicola Bonelli和Johannes Schaub的非常有用的答案,并将它们合并为一个解决方案,即恕我直言,更易读,更清晰,不需要typeof扩展:template&nbsp;<class&nbsp;Type>class&nbsp;TypeHasToString{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;This&nbsp;type&nbsp;won't&nbsp;compile&nbsp;if&nbsp;the&nbsp;second&nbsp;template&nbsp;parameter&nbsp;isn't&nbsp;of&nbsp;type&nbsp;T, &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;so&nbsp;I&nbsp;can&nbsp;put&nbsp;a&nbsp;function&nbsp;pointer&nbsp;type&nbsp;in&nbsp;the&nbsp;first&nbsp;parameter&nbsp;and&nbsp;the&nbsp;function &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;itself&nbsp;in&nbsp;the&nbsp;second&nbsp;thus&nbsp;checking&nbsp;that&nbsp;the&nbsp;function&nbsp;has&nbsp;a&nbsp;specific&nbsp;signature. &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;T,&nbsp;T>&nbsp;struct&nbsp;TypeCheck; &nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;char&nbsp;Yes; &nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;long&nbsp;No; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;A&nbsp;helper&nbsp;struct&nbsp;to&nbsp;hold&nbsp;the&nbsp;declaration&nbsp;of&nbsp;the&nbsp;function&nbsp;pointer. &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Change&nbsp;it&nbsp;if&nbsp;the&nbsp;function&nbsp;signature&nbsp;changes. &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;T>&nbsp;struct&nbsp;ToString &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;void&nbsp;(T::*fptr)(); &nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;T>&nbsp;static&nbsp;Yes&nbsp;HasToString(TypeCheck<&nbsp;typename&nbsp;ToString<T>::fptr,&nbsp;&T::toString&nbsp;>*); &nbsp;&nbsp;&nbsp;&nbsp;template&nbsp;<typename&nbsp;T>&nbsp;static&nbsp;No&nbsp;&nbsp;HasToString(...);public: &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;bool&nbsp;const&nbsp;value&nbsp;=&nbsp;(sizeof(HasToString<Type>(0))&nbsp;==&nbsp;sizeof(Yes));};我用gcc 4.1.2检查了它。这个功劳主要归功于Nicola Bonelli和Johannes Schaub,如果我的回答可以帮助你,请给他们一个投票:)
打开App,查看更多内容
随时随地看视频慕课网APP