1

以下 C++ 代码可以为 GNU g++、LLVM 和我扔给它的所有其他 C++ 编译器正确编译和运行,Microsoft VC6 和 VC7 除外:

template<typename A, typename B> int HasVoidReturnType(A(*)(B)) { return 0; }
template<typename B> int HasVoidReturnType(void(*)(B)) { return 1; }
void f(double) {}
int foo() { return HasVoidReturnType(f); }

对于 VC6 和 VC7,编译失败并报错:

f.cpp(4) : error C2667: 'HasVoidReturnType' : none of 2 overloads have a best conversion
    f.cpp(2): could be 'int HasVoidReturnType(void (__cdecl *)(B))'
    f.cpp(1): or       'int HasVoidReturnType(A (__cdecl *)(B))'
    while trying to match the argument list '(overloaded-function)'
f.cpp(4) : error C2668: 'HasVoidReturnType' : ambiguous call to overloaded function
    f.cpp(2): could be 'int HasVoidReturnType(void (__cdecl *)(B))'
    f.cpp(1): or       'int HasVoidReturnType(A (__cdecl *)(B))'
    while trying to match the argument list '(overloaded-function)'

与其争论什么编译器是正确的优点,我如何使用 VC6 和 VC7 从模板函数中确定函数是否具有 void 返回类型?

4

4 回答 4

3

试穿这个尺寸

template<typename FuncPtrType>
struct DecomposeFuncPtr;

template<typename ReturnType, typename ArgType>
struct DecomposeFuncPtr<ReturnType(*)(ArgType)> {
  typedef ReturnType return_type;
};

template<typename T>
struct is_void {
  enum { value = 0 };
};

template<>
struct is_void<void> {
  enum { value = 1 };
};

template<typename T>
int HasVoidReturnType(T dontcare) {
  return is_void< typename DecomposeFuncPtr<T>::return_type >::value;
}

它应该避免使 VC6/7 混乱的重载。

嗯。抱歉,我无法使用 VC6/7 对其进行测试。不过,我记得之前在 VC 中使用带有模板的函数指针遇到了问题。由于我们知道 A, B 适用于您原来的功能,我想知道是否类似:

template<typename T>
struct is_void {
  enum { value = 0 };
};

template<>
struct is_void<void> {
  enum { value = 1 };
};

template<typename A, typename B>
int HasVoidReturnType(A(*)(B)) {
  return is_void<A>::value;
}

会工作。

于 2009-02-07T19:32:00.240 回答
3

就 VC++ 6 而言,你被搞砸了,因为它不支持部分模板专业化,而这正是你解决这个问题所需要的。

于 2009-02-07T19:49:46.837 回答
0

您是否尝试过只使用第一个模板并使用模板专业化来定义第二个模板,而不是创建两个模板?

于 2009-02-07T19:15:14.347 回答
0

仅供参考,这可以在 Microsoft 的 C++ 2008 Express 版本上编译。(我很想帮忙,但无法在我的编译器上重现该问题)

于 2009-02-07T19:16:15.873 回答