首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Erwin Unruh的例子今天起作用了吗?

Erwin Unruh的例子今天起作用了吗?
EN

Stack Overflow用户
提问于 2018-02-18 07:33:26
回答 2查看 1.2K关注 0票数 2

下面是来自Erwin Unruh示例,它因使用C++模板元编程来生成编译器错误消息中的素数而闻名,如下所示。

代码语言:javascript
复制
// Erwin Unruh, untitled program, 
// ANSI X3J16-94-0075/ISO WG21-462, 1994.

template <int i>
struct D
{
    D(void *);
    operator int();
};

template <int p, int i>
struct is_prime
{
    enum { prim = (p%i) && is_prime<(i>2?p:0), i>::prim };
};

template <int i>
struct Prime_print
{
    Prime_print<i-1>    a;
    enum { prim = is_prime<i,i-1>::prim };
    void f() { D<i> d = prim; }
};

struct is_prime<0,0> { enum { prim = 1 }; };
struct is_prime<0,1> { enum { prim = 1 }; };
struct Prime_print<2>
{
    enum { prim = 1 };
    void f() { D<2> d = prim; }
};

void foo()
{
    Prime_print<10> a;
}

预期结果将是以下编译器错误消息:

代码语言:javascript
复制
// output:
// unruh.cpp 30: conversion from enum to D<2> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<3> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<5> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<7> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<11> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<13> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<17> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<19> requested in Prime_print

我检查了这段代码,并通过g++编译了它,没有得到相同的结果。

尽管我使用了c++17

代码语言:javascript
复制
g++ -std=c++17 -O3 main.cpp

似乎连c++03也不起作用。其结果与预期完全不同。我应该使用不同的编译器选项吗?

代码语言:javascript
复制
main.cpp:25:1: error: an explicit specialization must be preceded by ‘template <>’
 struct is_prime<0,0> { enum { prim = 1 }; };
 ^~~~~~~~~~~~~~~~~~~~
 template <> 
main.cpp:26:1: error: an explicit specialization must be preceded by ‘template <>’
 struct is_prime<0,1> { enum { prim = 1 }; };
 ^~~~~~~~~~~~~~~~~~~~
 template <> 
main.cpp:27:1: error: an explicit specialization must be preceded by ‘template <>’
 struct Prime_print<2>
 ^~~~~~~~~~~~~~~~~~~~~
 template <> 
main.cpp: In member function ‘void Prime_print<2>::f()’:
main.cpp:30:25: error: conversion from ‘Prime_print<2>::<unnamed enum>’ to non-scalar type ‘D<2>’ requested
     void f() { D<2> d = prim; }
                         ^~~~
main.cpp: In instantiation of ‘struct is_prime<0, 2>’:
main.cpp:14:25:   required from ‘struct is_prime<3, 2>’
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<0, 2>’ used in nested name specifier
     enum { prim = (p%i) && is_prime<(i>2?p:0), i>::prim };
                   ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp: In instantiation of ‘struct is_prime<4, 3>’:
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<4, 3>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<5, 4>’:
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<5, 4>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<6, 5>’:
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<6, 5>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<7, 6>’:
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<7, 6>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<8, 7>’:
main.cpp:20:25:   recursively required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<8, 7>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<9, 8>’:
main.cpp:21:10:   required from ‘struct Prime_print<9>’
main.cpp:20:25:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<9, 8>’ used in nested name specifier
main.cpp: In instantiation of ‘struct is_prime<10, 9>’:
main.cpp:21:10:   required from ‘struct Prime_print<10>’
main.cpp:35:21:   required from here
main.cpp:14:25: error: incomplete type ‘is_prime<10, 9>’ used in nested name specifier

更新1

正如用户替代码所建议的那样,存在一个Tony Delroy。我试过这段代码,但也不起作用。

代码语言:javascript
复制
template <int i>
struct D
{
    D(void *);
    operator int();
};

template <int p, int i>
struct is_prime
{
    enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0), i-1>::prim };
};

template <int i>
struct Prime_print
{
    Prime_print<i-1>    a;
    enum { prim = is_prime<i,i-1>::prim };
    void f() { D<i> d = prim ? 1 : 0; a.f(); }
};

struct is_prime<0,0> { enum { prim = 1 }; };
struct is_prime<0,1> { enum { prim = 1 }; };

struct Prime_print<2>
{
    enum { prim = 0 };
    void f() { D<1> d = prim? 1 : 0; }
};

int main()
{
    Prime_print<18> a;
    a.f()
}

更新2

我找到了一个工作代码这里。唯一的问题是它应该与grep级联才能给出结果。

代码语言:javascript
复制
g++ -std=c++03 -c -fpermissive main.cpp 2>&1 | grep "In instantiation"

输出:

代码语言:javascript
复制
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 17]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 13]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 11]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 7]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 5]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 3]’:
main.cpp: In instantiation of ‘void Prime_print<i>::f() [with int i = 2]’:

有没有办法不使用Linux grep命令就产生单行错误?

代码语言:javascript
复制
/*
  Prime number computation by Erwin Unruh
  http://www.erwin-unruh.de/Prim.html
  compatible with (now!) "valid" C++
  compile --> the error messages are the prime numbers up to 18!
  for clang: c++ unruh_new.cpp 2>&1 | grep -i error
  for gnu:   g++-mp-5 -std=c++03 -c                                \
                      -fpermissive                                 \
                      unruh_new.cpp 2>&1 | grep "In instantiation"
*/

template <int i> struct D { D(void*); operator int(); };

template <int p, int i> struct is_prime {
 enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0), i-1> :: prim };
};

template <int i> struct Prime_print {
 Prime_print<i-1> a;
 enum { prim = is_prime<i, i-1>::prim };
 void f() { D<i> d = prim ? 1 : 0; a.f();}
};

template<> struct is_prime<0,0> { enum {prim=1}; };
template<> struct is_prime<0,1> { enum {prim=1}; };

template<> struct Prime_print<1> {
 enum {prim=0};
 void f() { D<1> d = prim ? 1 : 0; };
};

#ifndef LAST
#define LAST 18
#endif

main() {
 Prime_print<LAST> a;
 a.f();
}
EN

回答 2

Stack Overflow用户

发布于 2019-02-26 11:00:03

下面是我在C++讲座中使用的更新程序。即使g++-8 -std=c++2a,它也运行得非常好(即,它会产生错误;-)。为了试用它,我建议使用以下脚本: w/o参数--在25之前得到素数,使用数值参数(例如,100) --得到素数到100。输出通过sed过滤,显示重要的行。如果需要编译器的所有输出,请提供任何第二个参数。

下面是脚本:

代码语言:javascript
复制
#!/bin/bash

if [ $# -eq 0 ] ; then
    last=25
else
    last=$1
fi

if [ $# -gt 1 ] ; then
   g++ --std=c++2a -DLAST=${last} primefrank.cc |& less
else
    (g++ --std=c++2a -DLAST=${last} primefrank.cc 2>&1) |
                                   grep 'instantiation of' |
                                   sed 's/ instantiation of//'
fi

以下是prorgram的来源:

代码语言:javascript
复制
#ifndef LAST
#define LAST 18
#endif

enum 
{
    IS_PRIME,
    NO_PRIME,
    CONTINUE  
};

template <int candidate, int testValue>
struct Eval
{
    enum
    { 
        mode = 
            testValue * testValue > candidate ? IS_PRIME  :    
            candidate % testValue == 0 ?        NO_PRIME  :
                                                CONTINUE
    };
};

template <int candidate, int prime, int mode >
struct sieve
{
    enum 
    { 
        next = prime + 1,
        isPrime = sieve<candidate, next, 
                        Eval<candidate, next>::mode>::isPrime
    };
};

template <int candidate, int prime> 
struct sieve<candidate, prime, IS_PRIME>
{
    enum { isPrime = IS_PRIME };
};

template <int candidate, int prime>
struct sieve<candidate, prime, NO_PRIME >
{
    enum { isPrime = NO_PRIME };
};

template <int prime>
struct test
{
    enum {isPrime = sieve<prime, 2, Eval<prime, 2>::mode>::isPrime };
};

template <int prime, int isPrime>
struct show
{                           
    static void f()
    {
        show<prime - 1, test<prime - 1>::isPrime >::f();
    }
};

template <int prime>
struct show<prime, IS_PRIME>
{
    static int *f()
    {
        show<prime - 1, test<prime - 1>::isPrime >::f();

        int x;
        return &x;
    }
};

template <>
struct show<1, IS_PRIME>
{
    static void f()
    {}
};

template <int prime>
void primes()
{
    show<prime, test<prime>::isPrime>::f();
}

int main() 
{
    // 'instantiation' messages because of the suggested grep command
    static_assert(LAST >= 2, 
        "instantiation of LAST must be >= 2");
    
    primes<LAST>();

    static_assert(0, 
        "instantiation of compilation terminated");
}
票数 3
EN

Stack Overflow用户

发布于 2018-02-18 07:50:27

在网上搜索,“发现现代的预览”( Discovering C++ )一书列出了struct is_prime中略有不同的源代码。

代码语言:javascript
复制
enum { prim = (p == 2) || (p%i) etc...

下一页列出了大量错误,如您文档中的错误,后面的页面显示了编译器的输出,该输出更简洁地列出了质数:

代码语言:javascript
复制
error: initializing argument 1 of ...whatever... [ with int i = 17 ]
error: initializing argument 1 of ...whatever... [ with int i = 13 ]
...and so on...

所以-我建议更仔细地看你的错误信息。然而,如何报告错误取决于您的编译器,并且可以合法地随版本而变化,因此编译器不产生您所期望的结果并不是错误的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48849447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档