[英]C++ Template: typename and function to map to int
I'm writing a C++ template that needs two params: typename T
, and an arbitrary function that maps T
to an unsigned int
. 我正在编写一个需要两个参数的C ++模板:
typename T
和一个将T
映射到unsigned int
的任意函数。
How can I declare and use a template that can do that? 如何声明和使用可以做到这一点的模板? I'd like to keep it simple, so that any dumb function can be used.
我想保持简单,以便可以使用任何哑函数。
UPDATE : 更新 :
Here is an example of what I'd like to do: 这是我想做的一个例子:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
And, in this file: 并且,在此文件中:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
Based on the answers, I tried writing code, but it won't compile. 根据答案,我尝试编写代码,但无法编译。 Or rather, the template will compile, but not the test which invokes it.
或更确切地说,模板将编译,但不会编译调用它的测试。
The template code looks like this: 模板代码如下所示:
template<typename T, typename f>
class C {
...f(T)...
...
The invocation code looks like: 调用代码如下:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
The error message is: 错误消息是:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
It seems like it's trying to use S's constructor for some reason, as opposed to using the operator()
which I want it to do. 似乎出于某种原因试图使用S的构造函数,而不是使用我想要它执行的
operator()
。
The purpose of the f parameter is that the SortedContainer needs to be able to position T by an integer value. f参数的目的是SortedContainer需要能够以整数值定位T。 T is not necessarily an integer or even Comparable, so the caller, when instantiating a SortedContainer, needs to pass not only type T, but a function f to transform T to an integer.
T不一定是整数,甚至不一定是Comparable,因此调用者在实例化SortedContainer时不仅需要传递类型T,还需要传递函数f来将T转换为整数。
The common way of doing this is to accept a general type F
for the function. 常用的方法是接受该函数的通用类型
F
This will allow any kind of function-like object, whether it is a function pointer or a class object with an overloaded operator()
. 这将允许任何类型的类似于函数的对象,无论是函数指针还是带有重载
operator()
的类对象。 So: 所以:
template<class T, class F>
class SortedContainer {
// ...
}
Compare with things like std::map
which does exactly this. 与之类似的
std::map
进行比较。
The disadvantage of this is that you cannot control what the prototype of the function is. 这样做的缺点是您无法控制该函数的原型。 This may or may not be a problem.
这可能是问题,也可能不是问题。 One way is just to use it as if it was
T
-to- unsigned int
and rely on the fact that the type system will catch any errors at the point of use. 一种方法就是使用它,就好像它是
T
unsigned int
并依赖于类型系统在使用时会捕获任何错误的事实。
Another way would be to verify the constraint with some kind of type trait. 另一种方法是使用某种类型特征来验证约束。 An example:
一个例子:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
Edit: I wrote a small example to convince myself i got the assert right, might as well post it. 编辑:我写了一个小例子,以说服自己我正确地主张了,不妨张贴它。 Here, using
A
will compile OK but B
will fail the assertion. 在这里,使用
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;
}
Based on your other edit: 根据您的其他编辑:
Note that the templated type F
only captures the type of the function. 请注意,模板化类型
F
仅捕获函数的类型 。 You still need an object of this type - the actual function - to call. 您仍然需要这种类型的对象 -实际函数-来调用。 Again, compare with
std::map
which first is templated to take a comparator type, and then has a constructor that takes an object of this type. 再次,与
std::map
比较,后者首先被模板化以采用比较器类型,然后具有构造器以采用该类型的对象。 This is true even if you use a normal function - the type will be SortedContainer<T, unsigned int (*)(T)>
, but you would somehow need to pass the actual function pointer into the container (probably through the constructor). 即使您使用普通函数也是如此-类型将为
SortedContainer<T, unsigned int (*)(T)>
,但是您将需要以某种方式将实际的函数指针传递到容器中(可能通过构造函数)。
Something like this: 像这样:
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();
}
It's as you said, pretty much: 就像您说的那样:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
if you actually wanted the argument to be a function pointer rather than a function, 如果您实际上希望参数是函数指针而不是函数,
template< typename T, unsigned int (*f)(T) >
and similarly if you want the argument to be a function reference. 同样,如果您希望参数作为函数引用。
(naturally, this will only work for dumb functions , not for function objects with an operator()
operator of the right signature) (自然,这仅适用于哑函数 ,不适用于具有正确签名的
operator()
运算符的函数对象)
You may use C-style function pointers as @Hurkyl suggests, or std::function
which probably can't be template parameters, but I think that idea is wrong. 您可以按照@Hurkyl的建议使用C样式的函数指针,也可以使用
std::function
,它们可能不能作为模板参数,但是我认为这种想法是错误的。
C++ templates are duck-typed, so STL code in many places ( std::unordered_map
-> std::hash
, std::sort
-> std::less
) relies on that. C ++模板是鸭子类型的,因此许多地方的STL代码(
std::unordered_map
> std::hash
, std::sort
> std::less
)都依赖于此。 I think you should also apply this approach - just ask user to provide specialization for type T: 我认为您也应该采用这种方法-只是要求用户为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, you don't require a separate template argument for Function F
. IMO,您不需要为
Function F
使用单独的模板参数。
template<typename T> // F not required!
class SortedContainer {
...
};
Choose a good name and use that function by overloading it for various cases. 选择一个好名字,并通过在各种情况下重载它来使用该功能。 eg
to_uint()
例如
to_uint()
Since you want to map (ie relate) a type to an unsigned int
( uint
), use following function in global scope: 由于您要将类型映射(即关联)到
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);
}
Scenario : For Sorted_Container<X>
, whenever to_uint(x)
is invoked, then: 场景 :对于
Sorted_Container<X>
,只要调用to_uint(x)
,则:
X
is a class, then it must have uint to_uint() const
method X
是一个类,则它必须具有uint to_uint() const
方法 X
is a POD, then you may have to overload to_uint()
for that type X
是POD,则可能必须为该类型重载to_uint()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.