初始化由C+中的引用变量捕获的+;兰姆达? 我有这个C++函数对象: static unsigned long long const FNV_OFFSET_BASIS = 14695981039346656037ul; static unsigned long long const FNV_PRIME = 1099511628211ul; struct fnv_hash { typedef unsigned long long value_type; fnv_hash( value_type *result ) { _result = result; *_result = FNV_OFFSET_BASIS; } void operator()( char c ) { // Fowler–Noll–Vo FNV-1a hash function *_result ^= c; // see: https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function *_result *= FNV_PRIME; } private: value_type *_result; };
可以像这样使用:初始化由C+中的引用变量捕获的+;兰姆达? 我有这个C++函数对象: static unsigned long long const FNV_OFFSET_BASIS = 14695981039346656037ul; static unsigned long long const FNV_PRIME = 1099511628211ul; struct fnv_hash { typedef unsigned long long value_type; fnv_hash( value_type *result ) { _result = result; *_result = FNV_OFFSET_BASIS; } void operator()( char c ) { // Fowler–Noll–Vo FNV-1a hash function *_result ^= c; // see: https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function *_result *= FNV_PRIME; } private: value_type *_result; };,c++,lambda,C++,Lambda,可以像这样使用: std::string const message = "hello, world"; hash::value_type hash_val; std::for_each( message.begin(), message.end(), fnv_hash( &hash_val ) ); 如果我想将函数对象转换为lambda,那么只有在构建底层编译器生成的lambda对象时,才会将捕获的变量hash_val初始化为FNV_OFFSET_BASIS。我
std::string const message = "hello, world";
hash::value_type hash_val;
std::for_each( message.begin(), message.end(), fnv_hash( &hash_val ) );
如果我想将函数对象转换为lambda,那么只有在构建底层编译器生成的lambda对象时,才会将捕获的变量hash_val
初始化为FNV_OFFSET_BASIS
。我唯一能想到的就是使用另一个lambda:
std::for_each( message.begin(), message.end(),
[&hv = [&hash_val]() -> decltype((hash_val)) {
return hash_val = FNV_OFFSET_BASIS; // Initialize and return reference to hash_val.
}() // Call the inner lambda.
]( char c ) {
hv ^= c;
hv *= FNV_PRIME;
}
);
这是可行的,但有没有更干净的方法
注:给出的示例仅用于教学目的。问题的关键在于如何“初始化”一个lambda,而不是如何解决这个特殊的hash示例
注意:“做不到”是可以接受的答案。如果有人问我类似的问题,我需要一个答案:在什么情况下,我们仍然应该使用函数对象而不是lambda?以牺牲一些效率为代价,您可以使用第二个传递值参数来初始化
hash\u val
:
std::for_each( message.begin(), message.end(),
[&hash_val, initialised = false](char c) mutable {
if (!initialised)
{
hash_val = FNV_OFFSET_BASIS;
initialised = true;
}
hash_val ^= c;
hash_val *= FNV_PRIME;
}
);
但是我更喜欢函子。你说你可以使用
std::acculate
这个事实只是为了这个特定的例子,但我对此表示怀疑。std::for_each
和std::acculate
之间唯一的真正区别在于std::acculate
使状态显式,包括处理初始化。我认为这是所有情况下的解决办法
static unsigned long long const FNV_OFFSET_BASIS = 14695981039346656037ul;
static unsigned long long const FNV_PRIME = 1099511628211ul;
struct fnv_hash {
typedef unsigned long long value_type;
value_type operator()(value_type _result, char c) { // Fowler–Noll–Vo FNV-1a hash function
_result ^= c; // see: https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
_result *= FNV_PRIME;
return _result;
}
};
int main() {
std::string const message = "hello, world";
fnv_hash::value_type hash_val
= std::accumulate( message.begin(), message.end(), FNV_OFFSET_BASIS, fnv_hash() );
}
accumulate
接受一个二进制运算符,但第一个参数是容器中的条目,第二个参数是您需要的任何状态:在您的例子中,它只是value\u type\u result
。尽管这一概念毫无疑问地扩展到了任意状态
现在,用lambda替换它显然是微不足道的:
value_type hash_val = std::accumulate( message.begin(), message.end(), FNV_OFFSET_BASIS,
[](value_type _result, char c) { // Fowler–Noll–Vo FNV-1a hash function
_result ^= c; // see: https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
_result *= FNV_PRIME;
return _result;
});
在lambda捕获变量之前,只需在声明变量的位置初始化该变量。lambda无需对其进行初始化,只需对其进行变异,例如:
使用hash\u value\u type=unsigned long;
静态哈希值类型常量FNV偏移量基础=14695981039346656037ul;
静态哈希值类型常量FNV素数=109951162811ul;
std::string const message=“你好,世界”;
散列值类型散列值=FNV偏移量基础;
std::每个(
message.begin(),message.end(),
[&hash_val](字符c){
hash_val^=c;
hash_val*=FNV_素数;
}
);
或者,使用std::accumulate()
而不是std::for_each()
,这样您甚至不需要捕获hash_val
变量,例如:
使用hash\u value\u type=unsigned long;
静态哈希值类型常量FNV偏移量基础=14695981039346656037ul;
静态哈希值类型常量FNV素数=109951162811ul;
std::string const message=“你好,世界”;
哈希值类型哈希值=标准::累加(
message.begin(),message.end(),
FNV_偏移量_基础,
[](哈希值类型值,字符c){
val^=c;
val*=FNV_素数;
返回val;
}
);
由于此时调用代码需要知道FNV\u OFFSET\u基
无论如何,在将其传递给lambda之前初始化hash\u val
不是最容易的吗?这看起来确实像是std::acculate
的作业。..@igortandtnik最容易?大概但我更喜欢保证用户不会出错的代码。@MooingDuck可以将示例替换为lambda需要一些初始状态的其他示例。对于这个特定的示例,我是否可以使用std::acculate
,这并不是问题的关键。您认为让用户编写两级lambda是一种改进吗?如果正确性是您的目标,为什么不保留命名的函数,fnv\u hash
?因为它封装得很好,所以需要一些努力才能正确使用。@PaulJ.Lucas:我刚才注意到了。完成。我对原始代码运行了lambda版本,但结果并不相同(尽管我不清楚有什么不同)。@PaulJ.Lucas,这就是结果错误的原因。参数必须是(值类型\u结果,字符c)
而不是(字符c,值类型\u结果)
@RemyLebeau:Whoopsie!:(