无法在模板参数中进行函数调用
Unable to make function call in template argument
下面的程序编译得很好。
#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;
}
$ 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;
^
据我说,这两个C++程序都是等效的。为什么第二个不编译,而第一个编译?
更新
一些答案是说std::sqrt()
通常不声明为constexpr
但在 gcc 上通过声明它constexpr
来扩展它。但它仍然没有回答我的问题。
如果std::sqrt()
没有声明为constexpr
,那么两个程序都应该无法编译。
如果std::sqrt()
在 gcc 中声明为constexpr
,则两个程序都应该成功编译。
为什么只有第一个程序编译,而第二个程序失败?
第一个程序可能会为您编译,但它不可移植,因为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
看起来b1
和b2
的声明应该以相同的方式处理,但模板参数的隐式转换规则比其他地方的隐式转换规则更严格。
根据标准,当模板参数的类型(此处,double
)与它被传递到的模板参数的类型(此处,std::size_t
)不同时,只允许一组有限的转换,即"转换后的常量表达式中允许的转换">([temp.arg.nontype]/5)。根据 [expr.const]/3,转换后的常量表达式只能涉及以下转换:
- 用户定义的转换
- 左值到重值转换
- 整体促销 除
- 缩小转换范围之外的积分转换
在此上下文中不允许浮点积分转换,即使在r
的初始化中也允许这样做。
相关文章:
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 函数调用C++中的参数太少
- 将参数打包的参数传递到 std::queue 中,以便稍后使用不同的函数调用
- 为什么即使我调用参数化构造函数也会调用默认构造函数?
- 调用参数排列不变函数 f(i++, i++)
- uncrustify:如何将多行 C 函数调用的参数组合到一行上?
- 函数调用中的参数过多
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 调用参数不是原子参数的函数是此代码引发异常的原因吗?
- 如何在C++中获取lua函数作为参数,然后调用它
- x64 函数调用参数推送/移动顺序 (MSVC)
- 函数调用参数列表 (C++) 中的空格
- 以可变类模板作为函数调用参数的函数模板参数推导
- 函数调用参数中的表达式交错到什么粒度
- 函数调用参数前的双哈希值
- 创建一个向量作为函数调用参数
- 函数调用参数中的构造函数样式转换
- 取消对拆分函数调用参数的信任