簡體   English   中英

“模擬”偏函數模板特化?

[英]“Simulate” Partial Function Template Specialization?

我知道部分模板特化不適用於函數。 但是有什么方法可以實現類似的目標嗎? 我的用例非常簡單,但我不確定解決它的最佳方法是什么。

假設我正在編寫一個接收 STL 容器的函數:

template<typename T>
void doSomething(T& container) {
    // do something here
}

現在,當std::forward_liststd::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::liststd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM