C++ 使用模板变量将模板推断为错误类型

C++ 使用模板变量将模板推断为错误类型,c++,templates,gcc,c++14,gcc5.2,C++,Templates,Gcc,C++14,Gcc5.2,因此,我有以下测试代码: struct empty_value{ template<typename T> T as(){ return T(0); } }; template<typename T, typename U, typename F> auto empty_func(empty_value lhs, empty_value rhs, F f) -> decltype(f(lhs.as<T>(), rhs.as<U&g

因此,我有以下测试代码:

struct empty_value{
    template<typename T>
    T as(){ return T(0); }
};

template<typename T, typename U, typename F>
auto empty_func(empty_value lhs, empty_value rhs, F f) -> decltype(f(lhs.as<T>(), rhs.as<U>())){
    return f(lhs.as<T>(), rhs.as<U>());
}

template<typename T, typename U, template<typename, typename> class F>
static auto bind_empty_f = std::bind(empty_func<T, U, F<T, U>>, std::placeholders::_1, std::placeholders::_2, F<T, U>{});

template<typename F>
void other_test_func(F&&){}

template<typename T, typename U, template<typename, typename> class F>
void test_func(){
    other_test_func(bind_empty_f<T, U, F>);
}

template<typename T, typename U>
struct my_add{
    decltype(auto) operator()(T lhs, U rhs){ return lhs + rhs; }
};

int main(){
    test_func<float, int, my_add>();
}
一切都很愉快。但是如果我调用
test\u func
,试图将其传递给
other\u test\u func
,我会得到一个错误,
std::bind
返回的基础类型无法转换为
float
。因此,它试图将其转换为实际函数的返回值。我不明白为什么。我在哪里传递函数的返回值


编辑 如果我在将局部变量的值设置为
bind\u empty\u f
后调用该函数,它首先编译:

int main(){
    auto var = bind_empty_f<float, int, my_add>;
    test_func<float, int, my_add>;
}
intmain(){
自动变量=bind\u empty\u f;
测试函数;
}
因此,问题必须与静态初始化有关,这是一个编译器错误

编辑2 如注释中所述,此示例使用其他编译器编译,但不使用原始测试编译器(GCC 5.2.0)

这是GCC 5.2或其他测试的编译器中的一个错误


因此,我想问题是,这是符合标准的代码吗?

这里是您问题的一个最小示例:

template<class T> struct tag {};

template<typename T>
static auto bind_empty_f = tag<T>{};

template<typename T>
decltype(bind_empty_f<T>) test_func(){
  return 3.14f;
}
模板结构标记{};
模板
静态自动绑定_empty_f=tag{};
模板
decltype(bind_empty_f)test_func(){
返回3.14f;
}
然后我们简单地
test_func()
并返回
3.14f
。如果我们
test\u func()
它将返回
3

如果我们首先执行
bind\u empty\u f
,则
test\u func
会生成错误

在另一个模板中调用时,为
bind\u empty\u f
推导的类型设置为
T
,而不是表达式右侧的类型

如果您直接调用它,并且尚未计算类型(似乎存在缓存),则会推断出正确的类型,并且my
test_func
无法生成(因为它尝试将
3.14f
转换为
bind
表达式类型,但失败)

这肯定是编译器的问题。您可以通过将
bind\u empty\u f
中的
auto
替换为
std::decay\u t
来解决此问题

请注意,一些绑定表达式还有其他问题,但它们不是这个问题的核心


,.

clang++和g++6编译您的code@PiotrSkotnicki我投票结束这个问题,因为它似乎是gcc开发版本中的一个bug。这将为他们的测试套件做一个有趣的测试,但不太可能帮助其他任何人。@CoffeeandCode您可能想让它们成为通用参考,但您是不正确的
empty_func
F
作为第三个类型参数传递,这将强制第三个函数参数精确为
F&&F
。转发引用(也称为通用引用)仅在类型推断上下文中“简单”工作;你没有做这种类型的演绎。@Yakk:你可能认为这是一种直觉;g++-5.1也接受了代码(),这让我觉得最新版本破坏了一些东西。正如我所说,我可能是错的,当然,在这种情况下,我很乐意撤回我的投票,或者酌情重新投票。
template<class T> struct tag {};

template<typename T>
static auto bind_empty_f = tag<T>{};

template<typename T>
decltype(bind_empty_f<T>) test_func(){
  return 3.14f;
}