我遇到与Passing different lambdas to function template in c++类似的问题,但现在使用由std::bind
而不是lambdas创建的包装器。
我有两个方法Add
的重载,采用不同形式的std::function
:
template<typename T>
struct Value
{
T value;
};
template <typename T>
void Add(Value<T> &value, function<bool()> predicate)
{
}
template <typename T>
void Add(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate)
{
}
这现在可以正常使用lambdas,但是使用std::bind
绑定的仿函数失败:
struct Predicates
{
bool Predicate0() { return true; }
bool Predicate1(const Value<int> &) { return true; }
};
Predicates p;
Add(i, std::bind(&Predicates::Predicate0, &p));
失败
错误C2668:&#39;添加&#39;:对重载功能的模糊调用
和
Add(i, std::bind(&Predicates::Predicate1, &p, _1));
使用静态断言失败(Visual C ++ 2015,Update 3):
元组索引越界
有没有办法让它与lambdas和绑定仿函数一起工作?我会考虑使用SFINAE来启用基于is_bindable_expression
的单个重载并检查参数类型,但我没有把它放在一起。
答案 0 :(得分:3)
我认为你不能做你想做的事。
您可以使用is_bind_expression
来检查您的参数是否是通过调用std::bind
生成的类型,但无法确定调用期望的参数数量。正如评论中提到的那样,这是std::bind
的一个特征:
如果调用
g()
时提供的某些参数不是 与g
中存储的任何占位符匹配,未使用的参数是 评估和丢弃。
这意味着两个重载都同样有效。
如果您不介意为所有bind
结果共享相同的重载,您可以传递所有参数并随意丢弃它们:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, std::false_type)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, std::false_type)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, std::true_type)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), std::is_bind_expression<std::decay_t<U>>{});
}
但这与使用布尔参数类似。在我看来,可读性更好地分配正确命名的标签:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, tag::default_)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, tag::default_)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, tag::bind)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), tag::get_tag<std::decay_t<U>>{});
}
标签定义为的
namespace tag
{
struct default_{};
struct bind{};
template<typename T, typename = void>
struct get_tag : default_ {};
template<typename T>
struct get_tag<T, std::enable_if_t<std::is_bind_expression<T>::value>> : bind {};
}
答案 1 :(得分:2)
停止使用std::bind
。这是乱七八糟的随机特征和怪癖。
今天的怪癖是std::bind
将接受无限数量的参数并丢弃任何额外的参数。明天你可能会遇到这样的事实:将std::bind
结果传递给std::bind
会产生奇怪的魔力。
boost
同时移植到bind
lambdas添加到语言中。 Lambdas解决了几乎所有问题bind
在语法清晰的情况下所做的事情,并且没有对auto
的怪癖感到害怕,特别是当auto
lambdas可用时,特别是在C ++ 14之后。 (大多数C ++ 11编译器也支持std::bind
lambda)。
您可以编写函数,以便在它们都适用时,其中一个或另一个是首选的重载。但这样做会给你的界面增加一堆噪音,在这种情况下,你想要这种偏好的唯一原因是因为std
做了一些愚蠢的事情。
围绕设计不良的std
库进行工程设计是不值得的。只需停止使用设计不良的template <class T, class F,
std::enable_if_t<
std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do pass f Value<T>
}
template <class T, class F,
std::enable_if_t<
!std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}
&& std::is_convertible<
std::result_of_t<std::decay_t<F> const&()>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do not pass f Value<T>
}
库,或在使用时明确使用。
如果做不到,请执行此操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_dict() {
FILE *fp;
int c;
char word[50];
char defn[500];
int sep = 0;
int doublenew = 0;
int i = 0;
fp = fopen("textfile.txt", "r");
if (fp == NULL) {
perror("Error in opening file");
return (-1);
}
while ((c = fgetc(fp)) != EOF) {
if (feof(fp)) {
break;
}
if (c == '.' && sep == 0) {
sep = 1;
word[i] = '\0';
//c = fgetc(fp);
i = 0;
} else
if (doublenew == 1 && c == '\n' && sep == 1) {
defn[i] = c;
i++;
defn[i] = '\0';
printf("%s %s", word, defn);
i = 0;
sep = 0;
doublenew = 0;
} else
if (c == '\n' && sep == 1) {
defn[i] = c;
doublenew = 1;
i++;
} else
if (sep == 0) {
word[i] = c;
i++;
} else
if (sep == 1) {
defn[i] = c;
i++;
doublenew = 0;
}
}
fclose(fp);
return 0;
}
我们会在你想要使用的两个重载中抛出一些令人讨厌的SFINAE检测,并明确地选择一个。
这不值得。