【问题标题】:Why compiler fails to understand the value of if branch at compile time?为什么编译器在编译时无法理解 if 分支的值?
【发布时间】:2014-08-02 23:20:47
【问题描述】:

我正在编写一个计算多维向量元素的函数

template<class T>
int real_size(const std::vector<T>& vec)
{
    int size=0;
    for(const auto& v : vec)
    {
        if(std::is_integral<T>::value ||
                std::is_floating_point<T>::value){
            size+=1;
        }
        else{
            size +=real_size(v);
        }
    }
    return size;
}

int main()
{
    std::vector<std::vector<int>> a(10);
    a[0]=std::vector<int>(10);
    std::cout<<real_size(a);
}

这给了我这些错误:

 error: no matching function for call to 'real_size(const int&)'
             size +=real_size(v);
                           ^

该代码似乎很好,错误无关紧要...... else 语句永远不应成为 size +=real_size(int);,因为我正在使用 std::is_integer 检查模板参数的类型。

但似乎编译器在编译时无法理解它!是编译器错误还是我犯了错误?

*我使用的是 gcc 4.8.1。 g++ -std=c++11 *

【问题讨论】:

  • else 子句中的代码不是有条件编译的。
  • 仅供参考:std::is_arithmetic
  • @xyz 不,不会的。您将 std::vector&lt;T&gt; 作为输入参数传递,将如何在递归调用中传递 T?
  • @FabioFracassi,我仍然认为static_if 使这样的代码比标签调度、SFINAE 或其他一些 TMP 方法更容易理解:/ 我确实看到它很容易被滥用,但如果使用得当,它可以使代码更短,并将内容保存在一个地方。

标签: c++ templates c++11


【解决方案1】:

如果将常量替换为实际值,您会看到编译错误是如何产生某种意义的。对于int,该代码等效于以下代码:

    if(true || false){
        size+=1;
    }
    else{
        size +=real_size(v);
    }

这里编译器仍然会抱怨 else 主体无效:死代码必须仍然是有效代码。

【讨论】:

  • 标准是这样说的吗?因为我在标准论文中找不到。
  • 找不到什么?说明整个程序必须格式良好的部分?
【解决方案2】:

该错误是因为else 分支仍需要编译。您可以将其更改为两个不同的函数,然后使用标签调度:

template<class T>
int real_size(const std::vector<T>& vec)
{
    int size=0;
    for(const auto& v : vec)
    {
        size += real_size_inner(std::is_arithmetic<T>(), v);
    }
    return size;
}

template<class T>
int real_size_inner(std::true_type, T&)
{
    return 1;
}

template<class T>
int real_size_inner(std::false_type, T& v)
{
    return real_size(v);
}

如果您对std::advance 在标准中的实现方式进行一些研究,您将了解它是如何工作的,因为它是以相同的方式实现的。

【讨论】:

    【解决方案3】:

    条件代码仍然被编译,并且必须是格式良好的,即使它可以在编译时确定它不会被执行。

    一种解决方案是为其他类型重载real_size

    template <typename T>
    typename std::enable_if<std::is_arithmetic<T>::value>::type
    real_size(T const &) {
        return 1;
    }
    

    并将你的循环减少到

    for(const auto& v : vec) {
        size += real_size(v);
    }
    

    【讨论】:

    • 你的意思是这样的? ideone.com/ef0Qcy,它给出了错误的结果,结果应该是 20 而不是 10
    • @xyz:根据您发布的(伪)代码的逻辑,它应该是 10:一个大小为 10 的 vector&lt;int&gt;(给出 10)和 9 个空的(每个给出零)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    相关资源
    最近更新 更多