我尝试做的事情:我有一个模板对象传入,作为界面的一部分,应该有一个"进程"用一些参数定义的函数(我不知道有多少)其中一些是模板参数。
即
struct A { static void process(int a); };
struct B { template <typename B0> static void process(int a, B0 b0); };
都是有效的处理程序。所以现在我需要检测处理程序的签名:静态类型参数和许多模板参数。
为此,我使用了许多模板魔法黑客,这些黑客可能会缩小到有问题的部分 - 检测一些模板参数(或只是检索模板化的签名)。
我试图找出所需信息的方法是使用Is it possible to write a template to check for a function's existence?
中描述的方法检查明确专门的签名struct _D;
template <typename T>
struct get_template_args_count
{
private:
template <int count> struct R { enum { value = count }; };
template <typename C>
static R<0> retrieve(decltype(&C::process));
template <typename C>
static R<1> retrieve(decltype(&C::template process<_D>));
template <typename C>
static R<-1> retrieve(...);
public:
typedef decltype(retrieve<T>(nullptr)) Result;
enum { value = Result::value };
};
int main(int argc, char* argv[])
{
std::cout
<< "A::process " << get_template_args_count<A>::value << "\n"
<< "B::process " << get_template_args_count<B>::value << "\n";
std::cin.get();
return 0;
}
使用clang(使用msvc2013或linux版本构建,使用gcc-4.9.2构建),它编译并输出:
A::process 0
B::process 1
使用msvc2012,它也会编译,但输出:
A::process 0
B::process -1
当通过评论后备案例(带有(...)的那个)进入角色时,msvc2012吓坏了:
main.cpp(28): error C2893: Failed to specialize function template 'get_template_args_count<T>::R<count> get_template_args_count<T>::retrieve(unknown)'
with [ T=B, count=1 ]
With the following template arguments: 'B'
v:\test\test\test\main.cpp(63) : see reference to class template instantiation 'get_template_args_count<T>' being compiled
with [ T=B ]
main.cpp(28): error C2893: Failed to specialize function template 'get_template_args_count<T>::R<count> get_template_args_count<T>::retrieve(unknown)'
with [ T=B, count=0 ]
With the following template arguments: 'B'
main.cpp(29): error C2825: 'get_template_args_count<T>::Result': must be a class or namespace when followed by '::'
with [ T=B ]
main.cpp(29): error C2039: 'value' : is not a member of '`global namespace''
main.cpp(29): error C2275: 'get_template_args_count<T>::Result' : illegal use of this type as an expression
with [ T=B ]
main.cpp(29): error C2146: syntax error : missing '}' before identifier 'value'
main.cpp(29): error C2143: syntax error : missing ';' before '}'
main.cpp(29): error C2365: 'value' : redefinition; previous definition was 'enumerator'
main.cpp(29) : see declaration of 'value'
(稍微重新格式化日志以减少行数)
我还尝试使用上述问题的评论中描述的不同技术(使用char [sizeof],使用typeof并将检查移动到返回类型中)无效 - 它产生相同的结果或甚至更奇怪的错误(包括&#34;意外的文件结尾和#34;没有明显的原因)分崩离析。
我还用另一种技术(通过SFINAE比较原型)检查了类似的问题Deduce variadic args and return type from functor template parameter (MSVC-specific),但是当我不确切知道时我无法看到如何使用它签名(即我不知道静态参数的数量和类型)。当然,我可能会强迫他们完成手头的特定任务,但是......
所以我有两个问题:
答案 0 :(得分:1)
这里的问题是MSVC拒绝提取在重载解析中使用的&C::template process<_D>
类型(注意没有任何有意义的错误消息)。它似乎认为instanciated函数只是一个函数的重载集;可能是一种实施方式。
您可以强制它将过载集转换为函数指针类型,方法是将其转换为函数参数:
template<typename T>
T* fn_id(T* func) {
return nullptr;
}
将T
展平为函数类型后,您可以将其用于decltype
。
template <typename C>
static R<1> retrieve(decltype(fn_id(&C::template process<_D>)));
通过这次黑客攻击,我获得了与你使用clang相同的输出。