2012-12-03 62 views
5

我注意到用於區分唯一模板函數的簽名與用於區分唯一函數(包括從模板函數實例化的函數)的簽名之間存在不對稱。如何區分只有返回類型不同的函數模板?

特別是,僅根據返回類型不同的模板函數被認爲是唯一的,而僅僅根據返回類型不同的函數被認爲是多餘的。

因此,我對如何,只有返回類型不同功能模板之間消除歧義,在實例化的點的對應問題:

#include <iostream> 

template<typename T> 
long foo(T) 
{ 
    std::cout << "long" << std::endl; 
    return 0; 
} 

template<typename T> 
char foo(T) 
{ 
    std::cout << "char" << std::endl; 
    return '\0'; 
} 

int main() 
{ 
    double d = 0.0; 
    long n = foo(d); // <- Ambiguous: How to specify the template function to use? 
} 

在上面的代碼中,模板函數foo的實例化正是因爲我剛纔提到的不對稱而模棱兩可。兩個模板函數定義的存在是合法的,但實例化是非法的,即使返回類型是在同一行代碼中指定的。

我這個問題純粹是爲了理論學習的目的。也許這個代碼在現實生活中會構成設計不佳的標誌。也許它在現實生活中永遠不會出現。另外,我可以設想通過更改模板定義(或進行其他更改)來克服此問題的不同方法。

但是,我仍然想知道如果保持模板定義不變,可以在實例化點處消除這兩個模板函數之間的歧義。

回答

6

使用模板時,您實際上可以消除兩種不同的重載。這是不漂亮,但工作原理:

long n = static_cast<long(*)(double)>(&foo)(d); 
+1

+1 ,從來沒有想過這個。醜陋但正確。順便說一句,'static_cast (foo)(d)'減少1個字符:) – iammilind

+0

完美。現在我對函數模板的信心得到了恢復。我開始想知道爲什麼函數模板簽名包含返回類型 - 如果它們不能被消除。但是,正如你傑出的答案所揭示的那樣,他們可以 –

1

如果你真的需要有具有相同的名稱,參數相同的列表,但返回類型不同二元函數模板,你別無選擇,只能通過將區分兩個返回鍵入模板參數:

template <typename R, typename T> 
R foo(T); 

IIRC在C++ 11中有部分功能模板專業化,儘管在標準中我找不到它。如果有,這應該工作:

//partial function template specializations: C++11 only! 
template <typename T> 
long foo<long, T>(T) 
{ 
    std::cout << "long" << std::endl; 
    return 0; 
} 

template<typename T> 
char foo<char, T>(T) 
{ 
    std::cout << "char" << std::endl; 
    return '\0'; 
} 

否則,在C++ 03:

template <typename R, typename T> 
struct FooImpl; 

template <typename T> 
struct FooImpl<long, T> 
{ 
    static long doIt(T) 
    { 
    std::cout << "long" << std::endl; 
    return 0; 
    } 
}; 

template <typename T> 
struct FooImpl<char, T> 
{ 
    static char doIt(T) 
    { 
    std::cout << "char" << std::endl; 
    return '\0'; 
    } 
}; 

template <typename R, typename T> 
R foo(T t) 
{ 
    return FooImpl<R, T>::doIt(t); 
} 

在這兩種情況下,你的主要應該是這樣的:

int main() 
{ 
    double d = 0.0; 
    long n = foo<long>(d); // specify the return type only 
    auto c = foo<char>(n); 
} 
相關問題