【发布时间】:2011-02-02 09:04:22
【问题描述】:
我遇到了一些用 VS7.1 编写的代码,现在我正试图让它在 MacOSX 上工作。下面我理解的代码sn-p是关于SFINAE原理的。据我了解,代码用于在编译时通过依赖一些模板实例化魔术来知道某物是什么类型。简而言之,通过查看模板参数来选择正确的重载。
这是我的代码。稍微简化以仅显示问题。
template <typename T>
struct SomeClass
{
};
template <>
struct SomeClass<char>
{
typedef char Type;
};
template <typename T>
struct IsChar
{
typedef char Yes;
typedef int No;
template <typename U>
static Yes Select(U*, typename SomeClass<U>::Type* p = 0);
template <typename U>
static No Select(U*, ...);
static T* MakeT();
const static bool Value = sizeof(Select(MakeT())) == sizeof(Yes);
};
我只是这样使用它:
if (IsChar<int>::Value)
{
...
在编译上面的代码运行良好时,由于在使用 int 时缺少 Type 的 typedef,它会选择最顶层的类。
如果我现在改用 char...
if (IsChar<char>::Value)
{
...
...编译器会抱怨 Select 函数模棱两可,因为它不知道该使用哪一个。从我读过的内容来看,重载决议最不喜欢省略号参数(...)。因此,它应该知道选择第一个。
代码至少在 VS7.1 上运行良好,但在 MacOSX 的 gcc 和 Linux 的 gcc4.4 上不行。
有什么建议可以解决这个问题吗?也许它通常以另一种方式完成?
谢谢!
更新:我意识到我提供的示例代码可能过于简化了,因为我相信即使我错误地让它看起来像那样,我们也不会在这里检查类型。今晚我必须为您收集更多信息,因为我这里没有代码。很抱歉。
UPDATE2:即使我的表现不佳,也是由于不熟悉原始代码或以这种方式使用模板。同时我挖掘了更多信息,假设这些构造由于某种原因而存在 X 并且我给出的名称都是错误的,那么编译器问题呢?为什么这里不能选择正确的重载函数?这也让我很感兴趣。正如我所说,我会更好地解释总体目标是什么。
编辑
仔细查看原始代码后,它使用了 boost::integral_constant 和 boost::enable_if,就像这里建议的那样。问题是特定于模板参数的推导方式,并且它没有按照设置的方式工作。但是,按照 Georg 在回答末尾的建议,我可以纠正一些事情以接受事情。我现在有以下内容:
typedef char Yes;
typedef int No;
template <typename U> static Yes Select(typename SomeClass<U>::Type* p);
template <typename U> static No Select(...);
static const bool Value = sizeof(Select<T>(0)) == sizeof(Yes);
这很好用。在进行一些试验时,我发现在 Select 函数中有两个函数参数会导致问题。我还没找到原因。当我更好地理解事情时,我会回到这个。
感谢您的所有帮助。至少我现在了解这里的原则以及事情应该如何运作。只是一些细节,还不得而知。
【问题讨论】:
-
你能稍微扩展一下你的代码吗?此外,您通常不希望将元谓词的结果作为 if 分支的值,因为错误分支中的代码将尝试使用不起作用的代码,您可以通过选择两个来拆分内容不同的功能。
IsChar是不是命名错误?它似乎并没有检查T是char。 -
@aaa:我在模板方面的技能水平已经超出了我的水平,所以您能否详细说明您对 enable_if 的引用的含义?谢谢。
-
@GMan:您能否详细说明在 if 中不使用它的意思?我在这里学习,所以我们需要慢慢来:)
-
我添加了一个补充答案。