[英]C++ Template: typename and function to map to int
我正在編寫一個需要兩個參數的C ++模板: typename T
和一個將T
映射到unsigned int
的任意函數。
如何聲明和使用可以做到這一點的模板? 我想保持簡單,以便可以使用任何啞函數。
更新 :
這是我想做的一個例子:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
並且,在此文件中:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
根據答案,我嘗試編寫代碼,但無法編譯。 或更確切地說,模板將編譯,但不會編譯調用它的測試。
模板代碼如下所示:
template<typename T, typename f>
class C {
...f(T)...
...
調用代碼如下:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
錯誤消息是:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
似乎出於某種原因試圖使用S的構造函數,而不是使用我想要它執行的operator()
。
f參數的目的是SortedContainer需要能夠以整數值定位T。 T不一定是整數,甚至不一定是Comparable,因此調用者在實例化SortedContainer時不僅需要傳遞類型T,還需要傳遞函數f來將T轉換為整數。
常用的方法是接受該函數的通用類型F
這將允許任何類型的類似於函數的對象,無論是函數指針還是帶有重載operator()
的類對象。 所以:
template<class T, class F>
class SortedContainer {
// ...
}
與之類似的std::map
進行比較。
這樣做的缺點是您無法控制該函數的原型。 這可能是問題,也可能不是問題。 一種方法就是使用它,就好像它是T
unsigned int
並依賴於類型系統在使用時會捕獲任何錯誤的事實。
另一種方法是使用某種類型特征來驗證約束。 一個例子:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
編輯:我寫了一個小例子,以說服自己我正確地主張了,不妨張貼它。 在這里,使用A
將編譯OK,但是B
將使斷言失敗。
#include <type_traits>
template<class T, class F>
class SortedContainer {
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
};
struct A {
unsigned int operator()(double) { return 0; }
};
struct B {
double operator()(double) { return 0; }
};
int main() {
SortedContainer<double, A> a;
SortedContainer<double, B> b;
}
根據您的其他編輯:
請注意,模板化類型F
僅捕獲函數的類型 。 您仍然需要這種類型的對象 -實際函數-來調用。 再次,與std::map
比較,后者首先被模板化以采用比較器類型,然后具有構造器以采用該類型的對象。 即使您使用普通函數也是如此-類型將為SortedContainer<T, unsigned int (*)(T)>
,但是您將需要以某種方式將實際的函數指針傳遞到容器中(可能通過構造函數)。
像這樣:
template<class T, class F>
class SortedContainer {
public:
SortedContainer(F f = F()): func(f) {}
void foo() {
// ...
func();
// ...
}
private:
F func;
};
struct A {
unsigned int operator()() { return 0; }
};
int main() {
A a;
SortedContainer<double, A> c(a);
c.foo();
}
就像您說的那樣:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
如果您實際上希望參數是函數指針而不是函數,
template< typename T, unsigned int (*f)(T) >
同樣,如果您希望參數作為函數引用。
(自然,這僅適用於啞函數 ,不適用於具有正確簽名的operator()
運算符的函數對象)
您可以按照@Hurkyl的建議使用C樣式的函數指針,也可以使用std::function
,它們可能不能作為模板參數,但是我認為這種想法是錯誤的。
C ++模板是鴨子類型的,因此許多地方的STL代碼( std::unordered_map
> std::hash
, std::sort
> std::less
)都依賴於此。 我認為您也應該采用這種方法-只是要求用戶為T型提供專門化:
/* Universal implementation */
template<typename T>
unsigned int sorted_container_weight(T t) { return t; }
template<typename T>
class SortedContainer {
T t;
public:
unsigned int somefunc() {
return sorted_container_weight(t);
}
};
template<>
unsigned int sorted_container_weight<Package>(Package p) { return p.w; }
SortedContainer<Package> sc;
IMO,您不需要為Function F
使用單獨的模板參數。
template<typename T> // F not required!
class SortedContainer {
...
};
選擇一個好名字,並通過在各種情況下重載它來使用該功能。 例如to_uint()
由於您要將類型映射(即關聯)到unsigned int
( uint
),因此請在全局范圍內使用以下函數:
template<typename T>
uint to_uint (const T& t) {
return t.to_uint(); // Must have `uint to_uint() const` member, else error
}
// Overloads of `to_uint()` for PODs (if needed)
template<typename T> // For all kinds of pointers
uint to_uint (const T* const pT) {
if(pT == nullptr)
<error handling>;
return to_uint(*pT);
}
場景 :對於Sorted_Container<X>
,只要調用to_uint(x)
,則:
X
是一個類,則它必須具有uint to_uint() const
方法 X
是POD,則可能必須為該類型重載to_uint()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.