2013-08-07 7 views
6

In una delle mie classi, sto cercando di usare std::priority queue con un lambda specificato per il confronto:Lambda per errore file di intestazione

#pragma once 
#include <queue> 
#include <vector> 

auto compare = [] (const int &a, const int &b) { return a > b; }; 
class foo 
{ 
public: 
    foo() { }; 
    ~foo() { }; 
    int bar(); 
private: 
    std::priority_queue< int, std::vector<int>, decltype(compare)> pq; 
}; 

mio programma viene compilato perfettamente fino a quando aggiungo un file .cpp per accompagnare l'intestazione:

#include "foo.h" 

int foo::bar() 
{ 
    return 0; 
} 

Questa volta, il mio compilatore genera un errore:

>main.obj : error LNK2005: "class <lambda> compare" ([email protected]@3V<lambda>@@A) already defined in foo.obj 

Perché non riesco a creare un file .cpp di accompagnamento se il mio file di intestazione contiene un lambda?

compilatore Visual Studio 2012

mio main.cpp:

#include "foo.h" 

int main(){ 
    return 0; 
} 
+5

Contrassegnalo 'const', in questo modo ha il collegamento interno per impostazione predefinita. O meglio ancora, rendilo un funtore. – Rapptz

+3

State dichiarando due globali entrambi chiamati 'compare' perché' foo.h' è incluso in due file sorgente separati. Sono d'accordo con Rapptz. – WhozCraig

+1

Non usare lambda in questo modo. Sono pensati per creare piccole funzioni locali, funzioni non generalmente utilizzate. Questo è meno leggibile di una funzione normale. – GManNickG

risposta

5

Come suggerito @Rapptz,

const auto compare = [] (const int &a, const int &b) { return a > b; }; 

risolto il problema. Perché?

Internal vs External linkage. Per impostazione predefinita, auto, come int dispone di collegamento esterno. Quindi, solo come:

int j = 5; 

In foo.h che in seguito sarebbe incluso per foo.cpp tiri un

Error 2 error LNK2005: "int j" ([email protected]@3HA) already defined in Header.obj

(VS 2013)

Tuttavia, const rende il legame interna di default, che significa che è accessibile solo in una unità di traduzione, evitando così il problema.

+0

Hanno passato un po 'di tempo a cercare di ottenerlo - risolto in 2 secondi in orizzontale! – davidhood2

0

Sono in grado di replicare questo problema per qualche motivo. Sto provando questo su VS2010 però - non sono sicuro se ciò ha fatto la differenza. In effetti, ho provato a includere l'intestazione in due file di origine e compila, collega e funziona bene.

Detto questo, si desidera prendere in considerazione l'utilizzo di std::function. In questo modo puoi definire il lambda nel codice cpp e non verrà definito più volte per qualsiasi motivo. (A proposito, da dove proviene il foo.obj? Hai un altro file sorgente che include questa intestazione?).

foo.h:

#pragma once 
#include <queue> 
#include <vector> 
#include <functional> 

typedef std::function<bool (int, int) > comptype; 
//auto compare = [] (const int &a, const int &b) { return a > b; }; 
class foo 
{ 
public: 
    foo() { }; 
    ~foo() { }; 
    int bar(); 

private: 
    std::priority_queue< int, std::vector<int>, comptype> pq; 
}; 

Poi più tardi nel cpp comprendere e definire il lambda e quando si crea il passaggio pq esso al costruttore.

foo.cpp:

auto compare = [] (const int &a, const int &b) { return a > b; }; 

foo::foo():pq(compare){} 

In questo modo non si è abilmente definire le più volte di funzione.

+0

Si tratta di un errore del linker, quindi 'foo.obj' è solo il file dopo la compilazione – yizzlez

Problemi correlati