无法在模板参数中进行函数调用

时间:2017-03-29 07:15:56

标签: c++ constants bitset

以下程序编译良好。

<div class="container">
    <h2>This is a sample — Line Chart</h2>
    <div>
        <canvas id="myChart"></canvas>
    </div>
</div>

 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js">
    var ctx = document.getElementById("myChart").getContext("2d");

    var myChart = new Chart(ctx, {
            type: 'line',
            data: {
                  labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
                  datasets: [{
                        label: '# of Votes',
                        data: [12, 19, 3, 5, 2, 3]
                             }]
                  },
            options: {
            scales: {
                  yAxes: [{
                        ticks: {
                             beginAtZero:true
                               }
                          }]
                    }
           }
       });
  </script>
#include <bitset>
#include <cmath>

int main()
{
    const int r = std::sqrt(100);
    std::bitset<r> n;
}

但是以下程序无法编译。

$ g++ -Wall -Wextra -pedantic -std=c++11 foo.cpp
$
#include <bitset>
#include <cmath>

int main()
{
    std::bitset<std::sqrt(100)> n;
}

据我所知,两个C ++程序都是等价的。那么为什么第二个不编译而第一个呢?

更新

有些答案是说$ g++ -Wall -Wextra -pedantic -std=c++11 bar.cpp bar.cpp: In function ‘int main()’: bar.cpp:6:31: error: conversion from ‘__gnu_cxx::__enable_if<true, double>::__type {aka double}’ to ‘long unsigned int’ not considered for non-type template argument std::bitset<std::sqrt(100)> n; ^ bar.cpp:6:31: error: could not convert template argument ‘std::sqrt<int>(100)’ to ‘long unsigned int’ bar.cpp:6:34: error: invalid type in declaration before ‘;’ token std::bitset<std::sqrt(100)> n; ^ bar.cpp:6:33: warning: unused variable ‘n’ [-Wunused-variable] std::bitset<std::sqrt(100)> n; ^ 通常不会被声明为std::sqrt(),但是gcc通过声明constexpr来扩展它。但它仍然没有回答我的问题。

如果constexpr未声明为std::sqrt(),则两个程序都无法编译。

如果在gcc中将constexpr声明为std::sqrt(),则两个程序都应该成功编译。

为什么只有第一个程序编译但第二个程序失败?

1 个答案:

答案 0 :(得分:3)

第一个程序可能会为您编译,但它不可移植,因为标准未将std::sqrt函数指定为constexpr。似乎海湾合作委员会决定将其constexpr

template<typename _Tp>
  inline _GLIBCXX_CONSTEXPR
  typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                  double>::__type
  sqrt(_Tp __x)
  { return __builtin_sqrt(__x); }

但是另一个标准库实现可能没有constexpr std::sqrt函数,所以你的第一个程序不会在那里编译。

让我们改为简化代码,并稍微修改一下,以便完全涉及相关概念:

constexpr std::size_t r = 10.0;
std::bitset<r> b1;      // OK
std::bitset<10.0> b2;   // ill-formed

看起来b1b2的声明应该以相同的方式处理,但模板参数的隐式转换规则比其他地方的隐式转换规则更严格。 / p>

根据标准,当模板参数的类型(此处为double)与传递给它的模板参数的类型(此处为std::size_t)不同时,只有受限制允许转换集,即“在转换的常量表达式中允许的转换”([temp.arg.nontype] / 5)。根据[expr.const] / 3,转换后的常量表达式只能涉及以下转换:

  • 用户定义的转化
  • 左值到右值的转化次数
  • 整体促销
  • 除了缩小转化次数之外的整数转化

在此上下文中不允许进行浮点积分转换,即使在r的初始化中允许它。