2013-08-07 14 views
6

W jednym z moich zajęć, staram się używać std::priority queue z określonym lambda dla porównania:Lambda w błąd pliku nagłówka

#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; 
}; 

Mój program kompiluje doskonale aż dodaję plik .cpp towarzyszyć nagłówek:

#include "foo.h" 

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

Tym razem mój kompilator generuje błąd:

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

Dlaczego nie mogę utworzyć dołączonego pliku .cpp, jeśli mój plik nagłówkowy zawiera znak lambda?

Kompilator Visual Studio 2012

My main.cpp:

#include "foo.h" 

int main(){ 
    return 0; 
} 
+5

Oznacz to jako "const", w ten sposób domyślnie ma wewnętrzne powiązanie. Albo jeszcze lepiej, spraw, żeby był funktorem. – Rapptz

+3

Deklarujesz dwa globale o nazwach 'compare', ponieważ' foo.h' jest zawarty w dwóch osobnych plikach źródłowych. Zgadzam się z Rapptz. – WhozCraig

+1

Nie używaj lambdas w ten sposób. Mają one na celu tworzenie małych lokalnych funkcji, a nie ogólnie używanych funkcji. Jest to mniej czytelne niż normalna funkcja. – GManNickG

Odpowiedz

5

Jak sugeruje @Rapptz,

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

rozwiązało problem. Czemu?

Internal vs External linkage. Domyślnie auto, podobnie jak int, ma powiązanie zewnętrzne. Tak, jak:

int j = 5; 

W foo.h które później być uwzględnione przez foo.cpp rzuca

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

(VS 2013)

Jednak const sprawia powiązania wewnętrzny domyślnie, która oznacza, że ​​jest dostępny tylko w jednej jednostce tłumaczeniowej, co pozwala uniknąć problemu.

+0

Spędziłem trochę czasu, próbując to zrobić - rozwiązałem go w 2 sekundy płasko! – davidhood2

0

jestem w stanie powtórzyć ten problem z jakiegoś powodu. Próbuję tego na VS2010 jednak - nie jestem pewien, czy to miało znaczenie. W rzeczywistości próbowałem dołączyć twój nagłówek do dwóch plików źródłowych i kompilował, łączył i działał dobrze.

To powiedziawszy, czy chcesz rozważyć użycie std::function. W ten sposób możesz zdefiniować lambdę w kodzie cpp i nie zostanie ona zdefiniowana wiele razy z jakiegokolwiek powodu. (BTW, skąd pochodzi foo.obj? Czy masz inny plik źródłowy, który zawiera ten nagłówek?).

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; 
}; 

Później w KPP to i zdefiniować lambda i podczas tworzenia pq przekazać je do konstruktora.

foo.cpp:

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

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

ten sposób nie jesteśmy zręcznie definiowania funkcji wielokrotnie.

+0

Jest to błąd łącznika, więc 'foo.obj' jest po kompilacji tylko plikiem – yizzlez

Powiązane problemy