【发布时间】:2017-11-19 14:45:35
【问题描述】:
我正在编写一个类模板,它将任意函数指针作为非类型模板参数。我想使用
template <auto F> struct Foo;
但我的编译器 (MSVC 2017.5) 不支持模板参数列表中的auto(尽管它支持许多 C++17 功能)。所以我以某种方式写了一个 hack:
template <typename T>
using Func = void (*)(T);
template <typename TF, TF F> struct Foo;
template <typename T, Func<T> F>
struct Foo<Func<T>, F> { ... };
#define FOO(func) Foo<decltype(func), func>
我实现了一个流操作符(用于QDebug 或任何其他文本流),如下所示:
template <typename T, Func<T> F>
QDebug &operator <<(QDebug &out, const FOO(F) &foo)
{
...
return out;
}
但是我的主代码找不到合适的operator<<重载:
void func(int) { ... }
...
FOO(&func) foo;
qDebug() << foo; // error
令人惊讶的是,当定义类似这样的运算符时,一切正常
QDebug &operator <<(QDebug &out, const Foo<Func<T>, F> &foo)
// ^^^^^^^^^^^^^^^
似乎最后一行中的Func<T> 和宏中的decltype<F> 给出的类型不同。但我检查了这一点,std::is_same_v<Func<int>, decltype(&func)> 给出了真实的答案。我想不出为什么使用宏 FOO 会给我任何其他编译时行为,就像不使用它时一样。
一个最小的工作示例:
#include <iostream>
template <typename T>
using Func = void (*)(T);
template <typename TF, TF F> struct Foo;
template <typename T, Func<T> F>
struct Foo<Func<T>, F> { };
#define FOO(func) Foo<decltype(func), func>
template <typename T, Func<T> F>
std::ostream &operator <<(std::ostream &out, const FOO(F) &foo)
// std::ostream &operator <<(std::ostream &out, const Foo<Func<T>,F> &foo)
{
return out;
}
void func(int);
int main(int argc, char **argv)
{
FOO(&func) foo;
std::cout << foo << std::endl; // error
}
【问题讨论】:
-
打开编译器的预处理器输出,看看
FOO宏产生了什么。这是预先查看正在编译的内容的唯一方法。 -
@PaulMcKenzie 产生
Foo<decltype(F), F>不是很“明显”吗?或者你是什么意思? -
不,这不是“显而易见的”。宏是邪恶的野兽,可以做你意想不到的事情。检查预处理器输出——没有其他替代品可以准确地查看编译器实际编译的内容。
-
@M.Winter 这不是最小的或完整的。您应该能够编写一个小程序来重现您的问题,例如,不依赖于 Qt。将代码片段分成多个块也很难回答,因为现在我们必须收集片段来重现。
标签: c++ templates operator-overloading overloading overload-resolution