it-swarm-eu.dev

Ukládání definic funkcí šablony C ++ do souboru .CPP

Mám nějaký kód šablony, který bych raději uložil do souboru CPP místo vloženého v záhlaví. Vím, že to lze provést, pokud víte, jaké typy šablon budou použity. Například:

. h soubor

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

soubor cpp

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

Všimněte si posledních dvou řádků - funkce foo :: do template se používá pouze u řetězců ints a std ::, takže tyto definice znamenají, že aplikace bude propojena.

Moje otázka zní - je to ošklivý hack, nebo bude fungovat s jinými kompilátory/linkery? Momentálně používám tento kód pouze s VS2008, ale budu chtít přenést do jiných prostředí.

441
Rob

Popisovaný problém lze vyřešit definováním šablony v záhlaví nebo pomocí výše popsaného přístupu.

Doporučuji přečíst následující body z C++ FAQ Lite :

O těchto (a dalších) tematických problémech jde do podrobností.

195
Aaron N. Tubbs

Pro ostatní na této stránce přemýšlel, jaká je správná syntaxe (jako jsem já) pro explicitní specializaci šablony (nebo alespoň ve VS2008), následující ...

Ve vašem .h souboru ...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

A v souboru .cpp

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;
103
namespace sid

Tento kód je dobře tvarovaný. Musíte pouze věnovat pozornost tomu, že definice šablony je viditelná v okamžiku vytvoření instance. Chcete-li citovat normu, § 14.7.2.4:

Definice nevyvážené funkční šablony, nevyvážené členské funkční šablony nebo nevyvážené členské funkce nebo statického datového prvku šablony třídy musí být obsažena v každé překladové jednotce, ve které je explicitně instancována.

19
Konrad Rudolph

To by mělo fungovat dobře všude, kde jsou podporovány šablony. Explicitní instance šablony je součástí standardu C++.

11
moonshadow

Váš příklad je správný, ale není příliš přenosný. Existuje také mírně čistší syntaxe, kterou lze použít (jak zdůraznil @ namespace-sid).

Předpokládejme, že templovaná třída je součástí některé knihovny, která má být sdílena. Měly by být kompilovány další verze templované třídy? Má správce knihovny předpokládat všechna možná templizovaná použití třídy?

Alternativní přístup je nepatrná variace na to, co máte: přidejte třetí soubor, který je soubor implementace/instanci šablony.

soubor foo.h

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

soubor foo.cpp

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

soubor foo-impl.cpp

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

Jedním z upozornění je, že musíte kompilátoru sdělit, aby kompiloval foo-impl.cpp místo foo.cpp, protože kompilace nic neudělá.

Ve třetím souboru můžete samozřejmě mít více implementací nebo více implementačních souborů pro každý typ, který chcete použít.

To umožňuje mnohem větší flexibilitu při sdílení templované třídy pro jiná použití.

Toto nastavení také zkracuje časy kompilace pro opětovně použité třídy, protože nemíte překompilovat stejný soubor záhlaví v každé překladové jednotce.

8
Cameron Tacklind

To rozhodně není ošklivý hack, ale uvědomte si, že budete muset udělat (explicitní specializace šablony) pro každou třídu/typ, který chcete použít s danou šablonou. V případě MANY typů vyžadujících instanci šablony může být v souboru .cpp MNOŽKA řádků. Chcete-li tento problém napravit, můžete mít TemplateClassInst.cpp v každém projektu, který používáte, abyste měli větší kontrolu nad tím, jaké typy budou instancovány. Je zřejmé, že toto řešení nebude dokonalé (aka stříbrná kulka), protože byste nakonec mohli porušit ODR :).

5
Red XIII

V nejnovějším standardu existuje klíčové slovo (export), které by pomohlo tento problém zmírnit, ale není implementováno v žádném kompilátoru, o kterém vím, kromě Comeau.

Podívejte se na to FAQ-lite .

4
Ben Collins

Specializace explicitní instanci. Jak jste uvedli, nemůžete vytvořit tuto šablonu s jinými typy. úpravy: opraveno na základě komentáře. .

Edit: corrected based on comment.

3
Lou Franco

Toto je standardní způsob, jak definovat funkce šablony. Myslím, že existují tři metody, které jsem četl pro definování šablon. Nebo pravděpodobně 4. Každý s klady a zápory.

  1. Definujte definici třídy. To se mi vůbec nelíbí, protože si myslím, že definice tříd jsou pouze orientační a měly by být snadno čitelné. Je však mnohem méně složité definovat šablony ve třídě než venku. A ne všechna prohlášení o šablonách jsou na stejné úrovni složitosti. Tato metoda také dělá z šablony skutečnou šablonu.

  2. Definujte šablonu ve stejné hlavičce, ale mimo třídu. Toto je můj nejčastěji preferovaný způsob. Udržuje přehlednou definici vaší třídy, šablona zůstává skutečnou šablonou. Vyžaduje však úplné pojmenování šablony, což může být složité. Váš kód je také k dispozici všem. Ale pokud potřebujete, aby byl váš kód inline, je to jediný způsob. Toho lze dosáhnout také vytvořením souboru .INL na konci definice vaší třídy.

  3. Zahrňte hlavičku.h a implementaci.CPP do svého main.CPP. Myslím, že to tak bylo. Nebudete muset připravovat žádné předběžné instance, bude se chovat jako skutečná šablona. Problém, který s tím mám, je, že to není přirozené. Normálně nezahrnujeme a neočekáváme zahrnutí zdrojových souborů. Myslím, že protože jste zahrnuli zdrojový soubor, funkce šablony mohou být vloženy.

  4. Tato poslední metoda, která byla zveřejněným způsobem, definuje šablony ve zdrojovém souboru, stejně jako číslo 3; ale namísto zahrnutí zdrojového souboru předinstancujeme šablony k těm, které budeme potřebovat. S touto metodou nemám problém a občas se to hodí. Máme jeden velký kód, nemůže těžit z inline, takže jej jednoduše vložte do souboru CPP. A pokud víme o společných instancích a můžeme je předdefinovat. To nás zachrání od psaní v podstatě stejné věci 5, 10krát. Výhodou této metody je zachování našeho kódu. Ale nedoporučuji vkládat malé, pravidelně používané funkce do souborů CPP. Tím se sníží výkon vaší knihovny.

Poznámka: Nevím o důsledcích nafouknutého souboru obj.

3

S příkladem, který jste uvedli, není nic špatného. Ale musím říci, že věřím, že není efektivní ukládat definice funkcí do souboru cpp. Chápu pouze potřebu oddělit deklaraci a definici funkce.

Při použití spolu s explicitní instancí třídy může knihovna Boost Concept Check Library (BCCL) pomoci vygenerovat kód funkce šablony v souborech cpp.

0
Benoît

Čas na aktualizaci! Vytvořte inline (.inl nebo pravděpodobně jakýkoli jiný) soubor a jednoduše do něj zkopírujte všechny své definice. Nezapomeňte přidat šablonu nad každou funkci (template <typename T, ...>). Nyní místo vložení souboru záhlaví do inline souboru uděláte opak. Přiložte vložený soubor po deklaraci vaší třídy (#include "file.inl").

Opravdu nevím, proč to nikdo nezmínil. Nevidím žádné okamžité nevýhody.

0
Didii