在C++中编译时计算和打印阶乘

26
template<unsigned int n>
struct Factorial {
    enum { value = n * Factorial<n-1>::value};
};

template<>
struct Factorial<0> {
    enum {value = 1};
};

int main() {
    std::cout << Factorial<5>::value;
    std::cout << Factorial<10>::value;
}

上面的程序在编译时计算阶乘值。我想使用cout在编译时打印阶乘值。我们如何实现在编译时打印阶乘值?

我正在使用VS2009。

谢谢!


为什么要用复杂的方式做简单的事情?如果你只需要计算阶乘,那就编写一个普通程序(不使用TMP),编译并运行它。 - Vlad
4
我正在学习TMP的基础知识,并想要在编译时查看结果,以确保逻辑正确。 - venkysmarty
@user:TMP 基本上是一种在编译时计算常量的方法。您希望以哪种形式输出结果?在预处理器中,这太早了(常量稍后计算),在“通常”的编译步骤中,您只能使用 cout 等方式输出结果(需要运行程序)。 - Vlad
4个回答

36

阶乘可以在编译器生成的消息中打印出来:

template<int x> struct _;
int main() {
        _<Factorial<10>::value> __;
        return 0;
}

错误信息:

prog.cpp:14:32: error: aggregate ‘_<3628800> __’ has incomplete type and cannot be defined _::value> __; ^

这里的 362880010 的阶乘。

可以在 ideone 上查看:http://ideone.com/094SJz

所以你是在寻找这个吗?


编辑:

Matthieu 请求一个巧妙的技巧,既能打印出阶乘,又能让编译继续进行。这是一种尝试。它不会导致任何错误,因此编译成功,只有一个警告。

template<int factorial> 
struct _{ operator char() { return factorial + 256; } }; //always overflow
int main() {
        char(_<Factorial<5>::value>());
        return 0;
}

代码编译时会有以下警告:

main.cpp: 在实例化 '_::operator char() [with int factorial = 120]' 时:main.cpp:16:39: required from here main.cpp:13:48: 警告:隐式常量转换中的溢出 [-Woverflow] struct _{ operator char() { return factorial + 256; } }; //always overflow

这里的 1205 的阶乘。

在 ideone 上的示例代码: http://coliru.stacked-crooked.com/a/c4d703a670060545

你可以编写一个好的宏,然后像下面这样使用:

#define PRINT_AS_WARNING(constant) char(_<constant>())    

int main() 
{
         PRINT_AS_WARNING(Factorial<5>::value);
         return 0;
}

看起来很棒


4
好的回答,但是你不应该使用保留符号(___)。 - Mike Seymour
4
代码的目的是引发错误。不要认为保留名称的事情适用于这里。 - Puppy
1
哦哇,这绝对是在编译时打印某些东西的方法。 :) 很好地利用了编译器,+1。 - Xeo
1
@Nawaz:不错 :) 你知道一个聪明的技巧,既可以在编译过程中打印结果,又可以让编译继续吗? - Matthieu M.
1
@Nawaz:这很聪明 :) 更妙的是 _ 可以用于输出任何结果......只要它是正数以确保它会溢出 :) - Matthieu M.
显示剩余6条评论

8

我正在学习TMP的基础知识,并希望在编译时得到结果,以确保逻辑正确。

这种情况下,您真正需要的是静态断言:

static_assert(Factorial<5> ::value ==     120,  "5! should be 120");
static_assert(Factorial<10>::value == 3628800, "10! should be 3628800");

如果您的编译器尚不支持static_assert,您可以使用BOOST_STATIC_ASSERT


1
错误。在更复杂的情况下(比如我想打印编译器推断出的复杂类型),我可能不知道确切的答案,甚至只是懒得打出来。 - ulidtko

4

我知道现在已经太晚了,但依然想说。

// definition
template<typename T, T N>
struct print_constexpr{
    [[deprecated]]
    print_constexpr(){ }
};

// usage
print_constexpr<unsigned int, Factorial<5>::value> x;

// output
{path to file}: warning: ‘print_constexpr<T, N>::print_constexpr() [with T = unsigned int; T N = 120]’ is deprecated [-Wdeprecated-declarations]
    print_constexpr<unsigned int, Factorial<5>::value> x;

0

没有标准的方法。我也想不到编译器特定的方法。

[ [占位符] ]


我甚至不确定是否有实际的方法。所有我所想到的#pragma message#warning通常会打印出该行,而不是计算结果 :/ - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接