【发布时间】:2014-01-14 22:04:10
【问题描述】:
我正在编写一些模板代码来确定是否可以将给定类型作为任何参数传递给任何可用的函数重载。在下面的示例中,我使用了 log 函数,但我也在数学库中的其他人身上尝试了此代码,结果是相同的。这个想法是使用函数重载和 sizeof 运算符来区分有问题的类型可以合法地传递给有问题的函数的情况(在本例中为日志)。
如果它成功了,当 'type' 可以合法地传递给 log 时,我们将拥有 sizeof(overload<type>(NULL)) == sizeof(True),否则将拥有 sizeof(overload<type>(NULL)) == sizeof(False)。这似乎对大多数类型都有效,但对std::string 无效。
这正是它失败的原因:
在正常情况下,我们应该有sizeof(overload<std::string>(NULL)) == sizeof(False)。但是,当我声明一个使用字符串的日志重载时,它仍然不会触发逻辑的 sizeof(True) 分支。请注意,我实际上并不想声明 log(std::string) 函数,我只是在测试这段代码以确保它能够检测到所有可能的重载。
起初我认为它只是没有正确检测过载,但是当我使用用户定义的类(下例中的“MyClass”)尝试它时,它运行良好:它在log(MyClass) 时产生了sizeof(True)被声明,否则 sizeof(False)。
#include <iostream>
#include <math.h>
template<int>
struct TakesInt{};
struct True
{
};
struct False
{
// guarantees that sizeof(False) != sizeof(True)
True array[2];
};
// takes anything; fall back if no match can be found
template<typename T>
False overload(...);
// takes a specific type; does not actually call log
template<typename T>
True overload(TakesInt<sizeof(log(T()))>*);
// As a test, this is an overload of log that takes a string.
// I don't actually want to implement this, but it should make the compiler
// think that a string is a valid argument.
double log(std::string);
// a placeholder for user defined class; could really be anything,
// like an arbitrary number class
struct MyClass{};
// declaring log for the arbitrary class above
// note that this is the same as for the log(std::string)
// if one works, the other should
double log(MyClass);
int main()
{
std::cout << sizeof(True) << '\t' << sizeof(False) << std::endl;
std::cout << sizeof(overload<std::string>(NULL)) << std::endl;
std::cout << sizeof(overload<double>(NULL)) << std::endl;
std::cout << sizeof(overload<MyClass >(NULL)) << std::endl;
return 0;
}
【问题讨论】:
-
听起来像是名称查找问题。
double log(std::string);不是从True overload(TakesInt<sizeof(log(T()))>*);的定义点通过非限定查找找到的,但是您自己的类型MyClass从实例化点通过ADL 找到。我刚刚验证了当您将log(std::string)的重载放在overload之前时,它将通过不合格的查找找到:Live example
标签: c++ string function templates overloading