有没有办法检测函数是否存在并且可以在编译时使用
Is there any way to detect whether a function exists and can be used at compile time?
编辑:对我问题的简短回答是,我对SFINAE可以做什么有一个错误的看法,它根本不检查函数体:sfinae是否实例化函数体?
我有一个与此类似的问题:是否可以编写一个模板来检查函数是否存在?
不同之处在于,我不仅要检查函数是否存在,而且还想知道它是否真的会通过 SFINAE。 以下是我试图完成的示例:
struct A
{
void FuncA() { std::cout << "A::FuncA" << std::endl; }
};
struct B
{
void FuncA() { std::cout << "B::FuncA" << std::endl; }
void FuncB() { std::cout << "B::FuncB" << std::endl; }
};
template<typename T>
struct Inter
{
void FuncA() { t.FuncA(); }
void FuncB() { t.FuncB(); }
T t;
};
// Always takes some sort of Inter<T>.
template<typename InterType>
struct Final
{
void CallFuncs()
{
// if( t.FuncA() exists and can be called )
t.FuncA();
// if( t.FuncB() exists and can be called )
t.FuncB();
}
InterType t;
};
void DoEverything()
{
Final<Inter<A>> finalA;
Final<Inter<B>> finalB;
finalA.CallFuncs();
finalB.CallFuncs();
}
请注意,在 CallFuncs() 中,FuncA() 和 FuncB() 将始终存在,但它们可能无法编译,具体取决于 Inter 中使用的类型 T。 当我尝试使用上面链接问题中的答案时,它似乎总是给我真实的,我猜是因为它只是检查函数是否存在,而不是它实际上可以编译(尽管我不能排除我没有搞砸什么......
为了有条件地调用我认为我可以enable_if这样的函数:
template<typename InterType>
typename std::enable_if< ! /* how to determine if FuncA can be called? */>::type TryCallFuncA( InterType& i )
{
}
template<typename InterType>
typename std::enable_if</* how to determine if FuncA can be called? */>::type TryCallFuncA( InterType& i )
{
i.FuncA();
}
template<typename InterType>
typename std::enable_if< ! /* how to determine if FuncB can be called? */>::type TryCallFuncB( InterType& i )
{
}
template<typename InterType>
typename std::enable_if</* how to determine if FuncB can be called? */>::type TryCallFuncB( InterType& i )
{
i.FuncB();
}
template<typename InterType>
struct Final
{
void CallFuncs()
{
TryCallFuncA(t);
TryCallFuncB(t);
}
InterType t;
};
但我不确定是否有任何方法可以让布尔值传递到enable_if。 有什么方法可以完成此操作,还是需要回退到某种手动维护的类型特征来指示函数是否存在?
就可用的 C++11 功能集而言,它的价值,我使用的是 MSVC 2010。
编辑:补充一个重要的说明,在我的实际情况中,类 Inter 的实现实际上是不透明的,我需要确定 Inter::FuncA/FuncB 是否会编译,所以我不能只是冒泡子类型并检查它们上是否存在函数。
没有时间检查这个,但您可以添加 Final
的专业化:template <typename T> struct Final< Inner<T> >;
(这也有助于确保类型始终是Inner
。有了它,您可以提取用于实例化的类型 Inter
.
现在第二个问题是如何使用 SFINAE 来检测成员函数是否存在。我相信这不应该太复杂(如果你不需要做这个通用):
// Find out whether U has `void f()` member
template <typename U>
struct has_member_f {
typedef char yes;
struct no { char _[2]; };
template<typename T, void (T::*)() = &T::f>
static yes impl( T* );
static no impl(...);
enum { value = sizeof( impl( static_cast<U*>(0) ) ) == sizeof(yes) };
};
你也许可以稍微扩展一下,让它更通用一些,但我认为函数的名称不能使它泛型。当然,您可以将其编写为生成has_member_##arg
并使用&T:: arg
的宏。成员的类型可能更容易概括...
或者,由于我认为这不能成为通用的,因此您可以直接在您的类型中使用内部has_member
技巧:提供两个callFuncA
重载,一个使用可选的第二个参数模板化,其中包含您想要的签名,默认为转发呼叫的&T::FuncA
,另一个带有省略号,即 noop。然后callFuncs
会呼叫callFuncA
并callFuncB
,SFINAE 将调度到转发器或中午,你会得到你想要的行为。
template<typename T>
struct Final< Inter<T> >
{
template <typename U, void (U::*)() = &U::FuncA>
void callFuncA( Inter<T>* x ) {
x.FuncA();
}
void callFuncA(...) {}
void CallFuncs() {
callFuncA(&t); // Cannot pass nonPOD types through ...
// Similarly TryCallFuncB(t);
}
Inter<T> t;
};
- 编译的C可执行文件被Windows defender检测为病毒
- CodeLite 不会检测(安装)MinGW - 即使使用手动配置也不会编译
- 检测编译时文本和常量
- 如何在编译时检测C 17中是否没有虚拟基础
- 有没有办法在编译时检测是否可以使用一组给定的参数类型成功调用通用 lambda?
- 编译时未检测到主要功能
- 参数类型的编译时类型检测
- 使用SFINAE检测编译时间是否存在过载的独立式功能
- 如何在编译时检测 C++ 代码中的 SQL 错误
- 如何在编译时检测ABI
- 我可以检测编译时使用的标记调度重载吗?
- 如何检测编译时是否shared_ptr类型
- 检测或避免在编译时间上暂时提及暂时的提及
- 在编译时检测std :: size_t类型以调用正确的功能
- 编译共享对象时出错:未检测到C++类定义
- 在编译时检测是否存在默认构造函数
- 编译弃用电话的时间检测
- 是否可以在编译时间作为宏上检测GCC编译标志
- 编译时解决方案以检测特征对象没有eval()成员
- 使用模板组合进行 CRTP 编译检测