7

更新:我在下面发布了我自己的答案, 这里有一个更长的版本:http: //scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-文字

问题:

我制作了一个简单的constexpr用户定义文字_X,将值作为 unsigned long long 获取(这就是数字用户定义文字的工作方式:http ://en.cppreference.com/w/cpp/language/user_literal ),然后我制作确保该值适合带符号的 long long。

这一切都很好(太大的值会导致编译错误),但只有当我明确创建一个变量时

constexpr auto a= 150_X;

相反,如果我写一些典型的东西,比如

cout << 150_X << endl;;

测试不在编译时执行。

  • 如果将 constexpr 函数分配给 constexpr 变量,它们是否仅在编译时执行?(我在标准中找不到)

  • 是否有可能实现_X我正在寻找的安全行为?

完整示例:

#include<iostream>
#include<stdexcept>

inline constexpr long long testConv(unsigned long long v) {
  return (v > 100 ) ? throw std::exception() : v; 
} // will eventually use actual limit from numeric_limits

inline constexpr long long operator "" _X(unsigned long long f) { 
  return testConv(f) ;
}

int main(){
  constexpr auto a= 5_X;
  std::cout << a << std::endl;
  std::cout << 200_X << std::endl;  // This bad literal is accepted at compile time
  constexpr auto c=250_X;           // This bad literal is not accepted at compile time
  std::cout << c << std::endl;
}

哦,供参考:我用的是gcc4.7.2。

4

3 回答 3

4

自我回答: 我找到了一个完整的解决方案,灵感来自我的问题的评论和其他答案,以及其他问题,例如https://stackoverflow.com/a/13384317/1149664

解决方案是使用用户定义文字的模板形式并手动将数字相加,将基于已解析数字的和乘以 10。

我在这里写了这个自我回答的详细版本:http: //scrupulousabstractions.tumblr.com/post/38460349771/c-11-type-safe-use-of-integer-user-defined-literals

template<char... Chars>
int operator"" _steps(){
  return {litparser<0,Chars...>::value};
}

Litparser 是一个小模板元程序,它将字符列表作为参数,从 Chars 参数包保存的输入字符扩展而来。

typedef unsigned long long ULL;

// Delcare the litparser 
template<ULL Sum, char... Chars> struct litparser;

// Specialize on the case where there's at least one character left:
template<ULL Sum, char Head, char... Rest>
struct litparser<Sum, Head, Rest...> {
// parse a digit. recurse with new sum and ramaining digits
  static const ULL value = litparser<
    (Head <'0' || Head >'9') ? throw std::exception() : 
    Sum*10 + Head-'0' , Rest...>::value;
};

// When 'Rest' finally is empty, we reach this terminating case
template<ULL Sum>  struct litparser<Sum> {
  static const ULL value = Sum;
};
于 2012-12-13T22:33:25.400 回答
3

constexpr函数可以在编译时执行;也就是说,它们有资格在常量表达式中使用。如果它们没有在常量表达式中使用,那么在编译时执行它们是没有意义的,尽管我认为这是允许的。

由于您不允许将参数声明为constexpr(第 7.1.5/1 节)[1],我认为没有任何方法可以operator "" _X(unsigned long long)在编译时强制评估,但您可以使用template<char...> operator "" _X()

如果constexpr在常量表达式中调用函数,则参数将是常量表达式(如果不是,则调用不是常量表达式)。但是,您不能通过将参数声明为来强制调用为常量表达式,因为您不允许将参数声明为,请参阅标准参考。constexprconstexpr


[注 1]:感谢 @LightnessRacesInOrbit 搜索标准以证明第二段中的主张是正确的。

于 2012-12-13T22:06:11.987 回答
1

constexpr 函数不需要在编译时执行。但是你的目标是可以实现的。为了更好地理解这个问题,以及一个如何创建一个总是在编译时评估的迭代的例子,我推荐这篇文章

于 2012-12-13T22:56:00.157 回答