簡體   English   中英

C ++模板:類型名和映射到int的函數

[英]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::hashstd::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 intuint ),因此請在全局范圍內使用以下函數:

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) ,則:

  1. 如果X是一個類,則它必須具有uint to_uint() const方法
  2. 否則,如果X是POD,則可能必須為該類型重載to_uint()
  3. 否則,編譯器將生成錯誤

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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