【问题标题】:template being deduced as wrong type with template variable模板被推断为带有模板变量的错误类型
【发布时间】:2015-09-09 17:07:44
【问题描述】:

所以我有以下测试代码:

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>();
}

这源于我实际从事的工作。问题出现在bind_empty_f 行。但仅当它传递给other_test_func 时。当我尝试将它分配给这样的常规变量时:

int main(){
    auto var = bind_empty_f<float, int, my_add>;
}

一切都很愉快。但是,如果我调用test_func 并尝试将其传递给other_test_func,我会收到一个错误,即std::bind 返回的基础类型无法转换为float。所以它试图将其转换为实际函数的返回值。我不明白为什么。我在哪里传递函数的返回值?


编辑

如果我在将局部变量设置为bind_empty_f 的值后调用该函数,首先它会编译:

int main(){
    auto var = bind_empty_f<float, int, my_add>;
    test_func<float, int, my_add>;
}

所以问题一定是与静态初始化有关编译器错误。

EDIT2

正如 cmets 中所述,这个确切的示例可以使用其他编译器编译,但不能使用原始测试编译器 (GCC 5.2.0)。

这是 GCC 5.2 或所有其他经过测试的编译器中的错误。

所以我想问题变成了,这个标准符合代码吗?

【问题讨论】:

  • clang++ 和 g++6 编译你的代码
  • @PiotrSkotnicki coliru doesn't
  • 我投票结束这个问题,因为它似乎是 gcc 开发版本中的一个错误。这将对他们的测试套件进行有趣的测试,但不太可能帮助其他任何人。
  • @CoffeeandCode 您可能打算将它们作为通用参考,但您不正确。 empty_func&lt;T, U, F&lt;T, U&gt;&gt;F&lt;T,U&gt; 作为第三个类型参数传递,这会强制第三个函数参数恰好是 F&lt;T,U&gt; &amp;&amp;f。转发引用(又名通用引用)仅在类型推导上下文中“简单地”起作用;你没有做这样的类型扣除。
  • @Yakk:你可能认为这是一种直觉; g++-5.1 也接受代码 (coliru.stacked-crooked.com/a/bac7fd419b6d6332),这让我觉得最新版本破坏了一些东西。正如我所说,我当然可能是错的,在这种情况下,我很乐意撤回我的投票或酌情重新投票。

标签: c++ templates gcc c++14 gcc5.2


【解决方案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;
}

然后我们只需 test_func&lt;float&gt;() 并返回 3.14f。如果我们test_func&lt;int&gt;() 它返回3

如果我们先执行bind_empty_f&lt;float&gt;,则test_func&lt;float&gt; 会生成错误。

bind_empty_f&lt;T&gt; 在另一个模板中被调用时推导出的类型设置为T,而不是表达式右侧的类型。

如果直接调用,并且类型还没有计算出来(好像有缓存),那么就推导出了正确的类型,我的test_func构建失败(因为它试图将 3.14f 转换为 bind 表达式类型并失败)。

这绝对是编译器的问题。您可以通过将bind_empty_f 中的auto 替换为std::decay_t&lt;decltype(stuff_on_rhs)&gt; 来解决此问题。

请注意,您的某些绑定表达式还存在其他问题,但它们不是此问题的核心。

live example compiling (wrongly), live example not compiling (correctly).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-07-07
    相关资源
    最近更新 更多