C ++ spínač není kompilace s externě definované proměnné použité jako případ

hlasů
5

Píšu C ++ pomocí MinGW GNU kompilátor a problém nastane, když se snažím používat externě definované celočíselné proměnné jako případu v příkazu switch. Mám následující chyba kompilátoru: „ případ štítek nesnižuje na celé číslo konstantní “.

Protože jsem definoval celočíselné proměnné jako extern mi věřit, že by měl sestavit, má někdo vědět, co může být problém?

Níže je uveden příklad:

test.cpp

#include <iostream>
#include x_def.h

int main()
{
   std::cout << Main Entered << std::endl;


   switch(0)
   {
      case test_int:
         std::cout << Case X << std::endl;
         break;
      default:
         std::cout << Case Default << std::endl;
         break;
   }

   return 0;
}

x_def.h

extern const int test_int;

x_def.cpp

const int test_int = 0;

Tento kód bude sestavovat správně na Visual C ++ 2008. Dále Montanan kamarád zkontrolovat ISO C ++ standard a zdá se, že jakýkoli const-integer výraz by měl fungovat. Je to možná i kompilátor chyby nebo jsem něco uniklo zřejmý?

Tady je moje informace kompilátor verze:

Čtení specifikace z C: / MinGW / bin /../ lib / gcc / mingw32 / 3.4.5 / specifikace
nakonfigurováno s: ../gcc-3.4.5-20060117-3/configure --with-gcc --with- gnu-ld --with-gnu-as --host = mingw32 --target = mingw32 --prefix = / mingw --enable-závity --disable-NLS --enable-jazyky = C, C ++, F77, ada, objc, java --disable-win32-registru --disable sdílený --enable-sjlj-výjimky --enable-libgcj --disable-java-awt --without-x --enable-java-GC = Boehm - disable-libgcj-debug --enable-interpreter --enable-hash-synchronizace --enable-libstdcxx-debug
model Téma: win32
gcc version 3.4.5 (mingw-vista speciální R3)

Položena 08/12/2009 v 22:29
zdroj uživatelem
V jiných jazycích...                            


8 odpovědí

hlasů
5

caseEtiketa vyžaduje integrální konstantní výraz , které mají přísné požadavky, které umožňují jejich hodnota se určí v době kompilace, na místě použití.

Z 5,19 [expr.const] „což je integrální konstantní výraz může zahrnovat pouze literals (2,13), sčítací komisaře, const proměnné nebo statické datové členy integrálních nebo sčítacích typů inicializována s konstantními výrazy (8,5), ...“.

V okamžiku, kdy budete používat test_int, kde je vyžadován konstantní výraz, to je constproměnná deklarována externa bez inicializátor a nesplňuje požadavky na konstantní výraz, a to navzdory skutečnosti, že jste skutečně inicializovat s integrovaným stálým výrazem v jiném překlad jednotka. (* To není ze znění normy zcela jasné, ale je můj současný výklad to.)

Omezení ve standardu zakázat zvyklostem, jako jsou:

void f(int a, int b)
{
    const int c = b;

    switch (a)
    {
    case c:
        //...
    }
}

Ve Vašem příkladu, kdy je kompilátor kompilace test.cpp, to nemá žádný způsob, jak určit, co Inicializátor může být v x_def.cpp. Možná jste udělal:

const int test_int = (int)time();

Je zřejmé, že v žádném z těchto příkladů by se hodnota const intse určí v době kompilace, která je záměrem pro integrální konstantní výrazy.

Odpovězeno 08/12/2009 v 22:41
zdroj uživatelem

hlasů
4

Case štítky musí být kompilace-časové konstanty. To znamená, že kompilátor musí být schopen nahradit hodnotu, při kompilaci. I když vaše hodnoty jsou konstantní, může překladač neví, jejich hodnoty, dokud alespoň link-time.

Odpovězeno 08/12/2009 v 22:34
zdroj uživatelem

hlasů
3

VC ++ je v pořádku, a g ++ je špatné. Případ nálepka musí být integral constant expression(§6.4.2 / 2) a const proměnná celé číslo typu inicializována s konstantním projevu je konstantní výraz (§5.19 / 1).

Edit: hlavně pro Pavla a jeho návrhu možného DR. §5.19 / 2 byl zcela přepsán již. C ++ 0x dodává zcela novou koncepci rámce constexpr, který rozšiřuje to, co je považováno za konstantní výraz značně. Například v rámci současného standardu, něco jako:

int x() { return 10; }
const int y = x();

ynení konstantní výraz. Můžeme snadno vidět, že je to (nepřímo) inicializuje doslovný 10, ale kompilátor stále nemůže dovolit to jako konstantní výraz. Podle nové normy, bude to možné označují x()jako constexpra ybude konstantní výraz.

Jak je to formulováno v N2960, §5.19 / 2 říká, že výraz je konstantní výraz, pokud používá něco z následujícího seznamu. To pak dává o stránce dlouhý seznam, ale s použitím constproměnné není inicializována v aktuální kompilace jednotky se nezdá být jedním z nich. [Edit: viz níže - čtení CWG Issue 721, změnil jsem názor.]

Pokud jde o VC ++ je vpravo a g ++ špatné, I slouží výhradně v tomto ohledu velmi specifické. Není pochyb o tom, že oba jsou „špatné“, pokud mluvíme o dostat každou část standardu správné. Pochybuji, že někdo to dokonce pracuje na realizaci exportbuď jeden.

exportdělá, nicméně, poukázat na míru, do jaké C ++ se zdá ochotni odložit rozhodnutí až do okamžiku propojení. Dvoufázové vyhledání názvu znamená, že když je exportován šablona sestaven, je tu mnohem víc, než jen ve stálých výrazech, že neví jistě. Mohlo by to ani neví, zda konkrétní název odkazuje na funkci nebo objekt - ale není pochyb o tom, že norma se vyžaduje přesně to. Tato otázka po ruce mi připadá jako podstatně jednodušší jeden řešit.

Edit: jsem trochu hledání a našel Working Group Jádro Issue 721. Jame otázka vyrovná jeden v ruce docela blízko ( "Nicméně, tato nevyžaduje, protože se podle všeho měl, že inicializace se vyskytují ve stejné jednotce překlad a předcházet konstantní výraz ... "). Navrhované řešení dodává frázi: „... s předchozí inicializaci ...“. Alespoň tak jsem to četl, to znamená, že se výbor dohodl, že za současného standardu, kód musí být přijata, ale pod novým standardem, že to není povoleno.

Tato formulace byla dohodnuta v červenci tohoto roku, ale není (zatím?) Se objeví v N2960, což je podle mého názoru nejvíce nedávný návrh C ++ 0x.

Odpovězeno 08/12/2009 v 22:40
zdroj uživatelem

hlasů
1

Nemohu reprodukovat na triviálním příkladu pomocí VC ++ 2008:

test.cpp:

extern const int n;
int main() {
    switch (0) {
    case n: break;
    }
}

test2.cpp:

extern const int n = 123;

kompilace s:

cl.exe test.cpp test2.cpp

výstup:

test.cpp (4): Chyba C2051: případ výraz není konstantní

Odpovězeno 08/12/2009 v 23:02
zdroj uživatelem

hlasů
1

MS kompilátor je tady trochu nemravné. Při kompilaci konstantní inicializaci a case pomocí konstantu ve stejné kompilační jednotce to vyjde na konstantní hodnotu v době kompilace.

Jakmile se pokusíte použít extern const mimo výpočtu jednotky, kde je to inicializované (tj obsahující inicializace cpp souboru nebo některý ze souborů, které zahrnuje) kompilátor barf se skoro stejné chyby. Fred Larson je správný kompilátor by neměla znát konstantní hodnotu až do okamžiku propojení a proto nesmí být přijatelný jako spínací konstanta, je to jen MS překladač podvádí trochu.

Řešení vašeho problému by bylo použití makra, je nějaký důvod, proč nechcete, aby #definekonstantní?

Odpovězeno 08/12/2009 v 23:00
zdroj uživatelem

hlasů
0

Vzhledem k tomu, C ++ 11 byste mohli postavit malý šablony rámce, aby vám syntaxi, jako je tento:

void test(int a, int x, int y, int z)
{
    std::cout << "given " << a << ", choosing ";
    given(a)
        .when(x, [] { std::cout << "x\n"; })
        .when(y, [] { std::cout << "y\n"; })
        .when(z, [] { std::cout << "z\n"; })
        .when(any_other, [] { std::cout << "none of the above\n"; });
}

Plná demo:

#include <iostream>


struct any_object {};
constexpr auto any_other = any_object {};

template<class Expr>
struct when_object
{

    template<class T, class F>
    constexpr when_object& when(T const& value, F&& f)
    {
        if (not executed and expr == value) {
            executed = true;
            f();
        }
        return *this;
    }

    template<class F>
    constexpr void when(any_object, F&& f)
    {
        if (not executed) {
            executed = true;
            f();
        }
    }

    Expr const& expr;
    bool executed = false;
};

template<class Expr>
constexpr auto given(Expr const& expr)
{
    return when_object<Expr> {expr};
}

void test(int a, int x, int y, int z)
{
    std::cout << "given " << a << ", choosing ";
    given(a)
        .when(x, [] { std::cout << "x\n"; })
        .when(y, [] { std::cout << "y\n"; })
        .when(z, [] { std::cout << "z\n"; })
        .when(any_other, [] { std::cout << "none of the above\n"; });
}


int main()
{
    test(4, 4, 5, 6);
    test(4, 3, 4, 5);
    test(4, 2, 3, 4);
    test(1, 2, 3, 4);
}

očekávané výsledky:

given 4, choosing x
given 4, choosing y
given 4, choosing z
given 1, choosing none of the above
Odpovězeno 16/01/2017 v 09:55
zdroj uživatelem

hlasů
0

Jsem pomocí „gcc (SUSE Linux) 4.3.2“ a které mají podobný účinek, že stále je trochu cizí.

Moje definice jsou:

namespace operations{
   const cOpDummy OpDummy();
   const cInitOperator InitOperator();
};

const unsigned long ulNumberOfOperations = 2;

const cOperation * arrayOperations[] = {
   & (operations::OpDummy),
   & (operations::InitOperator)
};

A externí prohlášení v jiném souboru, jsou:

extern const unsigned long ulNumberOfOperations;
extern const cOperation * arrayOperations[];

Legrační je: kompilátor dává jen „ulNumberOfOperations“ „definován odkazem na ulNumberOfOperations“, ale je v pořádku s „arrayOperations []“. Moje řešení je prohlásit „ulNumberOfOperations“ není konstantní.

Odpovězeno 01/04/2010 v 17:50
zdroj uživatelem

hlasů
0

Zde je jednodušší test:

test_int.cpp:

const int test_int = 10;

main.cpp:

#include <iostream>
using std::cout;
using std::endl;

extern const int test_int;

int main() {
    cout << test_int << endl;
    return 0;
}

V G ++, objeví se nedefinovaný odkaz. Nicméně, dělat to samé v C funguje. Podle http://gcc.gnu.org/ml/gcc/2005-06/msg00325.html , const proměnná implicitně vnitřní vazby v C ++. To se nezdá být případ v C.

Odpovězeno 08/12/2009 v 22:48
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more