[英]“Simulate” Partial Function Template Specialization?
我知道部分模板特化不適用於函數。 但是有什么方法可以實現類似的目標嗎? 我的用例非常簡單,但我不確定解決它的最佳方法是什么。
假設我正在編寫一個接收 STL 容器的函數:
template<typename T>
void doSomething(T& container) {
// do something here
}
現在,當std::forward_list
和std::list
被傳std::forward_list
,我想要這個函數的不同定義。
起初我想也許我可以像這樣重載函數:
// overload for std::list
template<typename T>
void insertionCppStl(std::list<T>& container) {
// do seomthing here for list
}
但這意味着我也需要對std::forward_list
執行相同的重載。 這一點都不理想。
有沒有辦法為兩種不同的輸入類型重載一個函數? 尋找 C++17 的答案,但也歡迎 C++20 的答案。
不是一個很好的解決方案,但是......
template <template <typename...> class C, typename T>
std::enable_if_t<std::is_same_v<C<T>, std::list<T>>
|| std::is_same_v<C<T>, std::forward_list<T>>>
insertionCppStl (C<T> & container) {
// do seomthing here for list
}
(注意:代碼未經測試)
正如 Daniel Langr 所指出的(謝謝!)這僅適用於具有標准分配器的列表,因此對於std::list<T>
和std::forward_list<T>
,不適用於std::list<T, A>
和std::forward_list<T, A>
其中A
是不同於std::allocator<T>
。
這對您來說是否足夠,取決於您的需要。
一個更通用的解決方案也可以考慮分配器
template <template <typename...> class C, typename T, typename A>
std::enable_if_t<std::is_same_v<C<T, A>, std::list<T, A>>
|| std::is_same_v<C<T, A>, std::forward_list<T, A>>>
insertionCppStl (C<T, A> & container) {
// do seomthing here for list
}
顯然這僅適用於std::list
和std::forward_list
。
正如 Barry 在評論中指出的(謝謝!),當您有兩個(三個、四個……)類型具有共同點(在這種情況下:具有兼容簽名的模板類型)但不是一個一般解決方案。
不幸的是,我沒有看到一個簡單的通用解決方案......我建議開發一個特定的 type_traits 來為函數的特定版本選擇可接受的類型。
例如:如果您想要std::list
s、 std::forward_list
s 和std::array
s 的特定版本,您可以編寫如下內容
template <typename>
struct specific_foo : public std::false_type
{ };
template <typename T, typename A>
struct specific_foo<std::list<T, A>> : public std::true_type
{ };
template <typename T, typename A>
struct specific_foo<std::forward_list<T, A>> : public std::true_type
{ };
template <typename T, std::size_t N>
struct specific_foo<std::array<T, N>> : public std::true_type
{ };
然后是foo()
函數的兩個版本:特定版本(接收std::true_type
作為第二個參數)和通用版本(接收std::false_type
template <typename T>
void foo (T const &, std::false_type)
{ std::cout << "generic version" << std::endl; }
template <typename T>
void foo (T const &, std::true_type)
{ std::cout << "specific version" << std::endl; }
現在你需要一個標簽調度版本的foo()
來為第二個參數選擇正確的類型
template <typename T>
void foo (T const & t)
{ foo(t, specific_foo<T>{}); }
下面是一個完整的編譯示例
#include <list>
#include <array>
#include <vector>
#include <iostream>
#include <type_traits>
#include <forward_list>
template <typename>
struct specific_foo : public std::false_type
{ };
template <typename T, typename A>
struct specific_foo<std::list<T, A>> : public std::true_type
{ };
template <typename T, typename A>
struct specific_foo<std::forward_list<T, A>> : public std::true_type
{ };
template <typename T, std::size_t N>
struct specific_foo<std::array<T, N>> : public std::true_type
{ };
template <typename T>
void foo (T const &, std::false_type)
{ std::cout << "generic version" << std::endl; }
template <typename T>
void foo (T const &, std::true_type)
{ std::cout << "specific version" << std::endl; }
template <typename T>
void foo (T const & t)
{ foo(t, specific_foo<T>{}); }
int main ()
{
foo(0); // print "generic version"
foo(std::list<int>{}); // print "specific version"
foo(std::forward_list<long>{}); // print "specific version"
foo(std::array<long long, 42u>{}); // print "specific version"
foo(std::vector<char>{}); // print "generic version"
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.