我正在編寫一些模板代碼以確定給定類型是否可以作爲任何可用的函數重載參數傳遞。在下面的例子中,我使用了日誌功能,但是我也在數學庫中的其他人上嘗試了這些代碼,結果是一樣的。我們的想法是使用函數重載和sizeof運算符來區分哪些類型可以合法地傳遞給有問題的函數(在本例中爲log)。在模板代碼中未檢測到std :: string的重載
如果有效,我們可以有sizeof(overload<type>(NULL)) == sizeof(True)
,當'type'可以合法地傳遞到日誌時,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;
}
聽起來像名稱查找問題。從'True overload'(TakesInt *);'定義的角度看,通過非限定的查找找不到'double log(std :: string)從實例化的角度來看,通過ADL可以找到MyClass。我只是驗證了當你在'overload'之前加載'log(std :: string)'的重載時,它會通過非限定查找找到:[Live example](http://coliru.stacked-crooked。com/a/17d44cadd598a97c) –
dyp