Czy ma sens używanie wbudowanych słów kluczowych w szablonach?

119

Ponieważ szablony są zdefiniowane w nagłówkach, a kompilator jest w stanie określić, czy wstawianie funkcji jest korzystne, czy ma to jakiś sens? Słyszałem, że współczesne kompilatory wiedzą lepiej, kiedy wstawić funkcję i ignorują inlinewskazówkę.


edycja: chciałbym zaakceptować obie odpowiedzi, ale nie jest to możliwe. Aby zamknąć sprawę, przyjmuję odpowiedź phresnela , ponieważ otrzymał on najwięcej głosów i formalnie ma on rację, ale jak wspomniałem w komentarzach, uważam, że odpowiedzi Szczenięcia i Komponentu 10 również są poprawne, z innego punktu widzenia .

Problem tkwi w semantyce C ++, która nie jest ścisła w przypadku inlinesłów kluczowych i inliningu. phresnel mówi „pisz w tekście , jeśli masz to na myśli”, ale to, co właściwie oznacza, inlinenie jest jasne, ponieważ ewoluowało od pierwotnego znaczenia do dyrektywy, która „powstrzymuje kompilatory narzekanie na naruszenia ODR”, jak mówi Puppy .

doc
źródło

Odpowiedzi:

96

Nie jest to bez znaczenia. I nie, nie każdy szablon funkcji jest inlinedomyślny. Norma jest nawet wyraźnie o tym mowa w specjalizacji jawnej ([temp.expl.spec])

Mają następujące cechy:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (zaczerpnięte z Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Skompiluj to i voila:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Brak informacji inlinepodczas wykonywania jawnej instancji może również prowadzić do problemów.

Podsumowując : w przypadku nie w pełni wyspecjalizowanych szablonów funkcji, czyli takich, które zawierają co najmniej jeden nieznany typ, można pominąć inlinei nie otrzymać błędów, ale tak nie jest inline. W przypadku specjalizacji pełnych, czyli wykorzystujących tylko znane typy, nie można tego pominąć.

Proponowana praktyczna zasada : pisz, inlinejeśli masz to na myśli i bądź konsekwentny. Sprawia, że ​​mniej myślisz o tym, czy chcesz, czy nie, tylko dlatego, że możesz. (Ta praktyczna zasada jest zgodna z szablonem C ++ Vandevoorde'a / Josuttisa : kompletny przewodnik ).

Sebastian Mach
źródło
2
Można by było napisać, prawda. Ale to nie oznacza nieliniowości, nawet jeśli na to wygląda. Vandevoorde i Josuttis również dokładnie to stwierdzają w C ++ Templates: The Complete Guide
Sebastian Mach
43
Wyraźna specjalizacja nie jest szablonem.
Puppy
2
@DeadMG: Jednak podczas wyszukiwania preferowana jest normalna funkcja zamiast pełnej specjalizacji, więc jeśli nie są szablonami ani szablonami, czym one są?
Sebastian Mach
13
Ta odpowiedź jest nieprawidłowa. Jawna specjalizacja szablonu to funkcja, a nie szablon. Ta funkcja nie staje się inlinetylko dlatego, że wyspecjalizowany szablon jest oznaczony inline. Więc inlinena szablonie jest całkowicie nieistotne. To, czy ta funkcja powinna być, inlineczy nie, nie ma nic wspólnego z generowaniem jej przez specjalizację szablonu (a są lepsze odpowiedzi niż ten adres, kiedy należy jej użyć inline). Odpowiedź @Puppy poniżej jest poprawna, ta nie. Dodanie inlinedo szablonu jest nieistotne i clang-tidyfaktycznie go usunie.
gnzlbg
6
Ponadto przykład pokazuje tylko problemy z ODR dla normalnych funkcji (zachowanie nie ma nic wspólnego z szablonami). Próba pokazuje, że inlinenie jest bez znaczenia, przykład powinny obejmować przypadku wyraźnie specjalizujący się template<> void f<>(int) {} bez tej inlinehasła. Ale nawet wtedy zmiana inlinespecyfikatora w szablonie nie robi żadnej różnicy, ponieważ to, czy zaznaczysz szablon, inlineczy nie, nie ma znaczenia.
gnzlbg
34

To nieistotne. Wszystkie szablony już są inline- nie wspominając, że od 2012 roku jedynym zastosowaniem inlinesłowa kluczowego jest zatrzymanie kompilatorów narzekających na naruszenia ODR. Masz absolutną rację - Twój kompilator obecnej generacji sam wie, co wstawić i prawdopodobnie może to zrobić nawet między jednostkami tłumaczeniowymi.

Szczeniak
źródło
11
Standard nie stwierdza, że ​​wszystkie szablony są wbudowane.
Sebastian Mach
16
@phresnel: Ale szablony mają tę samą semantykę, co inlinefunkcje ze znakiem -mark (to znaczy, wiele równoważnych definicji może być przekazanych do konsolidatora, który wybierze jedną). To, a nie inlining, jest prawdziwą funkcją inlinesłowa kluczowego.
Ben Voigt,
2
@BenVoigt: Wiem o znaczeniu ODR inline. Może rzuć okiem na moją odpowiedź poniżej (lub powyżej, w zależności od wybranego sortowania). W przypadku szablonów niespecjalistycznych masz oczywiście rację, ale formalnie to nie to samo.
Sebastian Mach,
3
@DeadMG: W C ++ nie ma wymogu, aby szablon funkcji musiał być zaimplementowany w pliku nagłówkowym; można go wdrożyć w dowolnym miejscu. Aby to odzwierciedlić, zalecam tagowanie inlinetego, co powinno być w tekście. Zwykle nie ma to znaczenia, ale w standardowym języku nie są one takie same i nie wszystkie są wbudowane. Akceptuję Twoje stanowisko mówiąc „To nieistotne”, ale zgodnie ze standardem nie wszystkie szablony są wbudowane, tylko dla Ciebie jako użytkownika C ++ - wyglądają tak, jakby.
Sebastian Mach
7
Twój komentarz na temat zaakceptowanej odpowiedzi, że wyraźna specjalizacja nie jest szablonem (co jest oczywiste po powiedzeniu o tym, oczywiście ...), jest prawdopodobnie najbardziej pomocną rzeczą na tej stronie. Czy mógłbyś dodać to również do swojej odpowiedzi?
Kyle Strand
6

Jak zasugerowałeś, inline jest wskazówką dla kompilatora i niczym więcej. Może ją zignorować lub w rzeczywistości wstawiać funkcje nieoznaczone jako wbudowane.

Używanie inlinez szablonami było kiedyś (słabym) sposobem obejścia problemu, że każda jednostka kompilacji tworzyłaby oddzielny obiekt dla tej samej klasy z szablonami, co powodowałoby problemy z powielaniem w czasie łączenia. Używającinline (myślę), że zniekształcenie nazwy działa inaczej, co powoduje konflikt nazw w czasie łącza, ale kosztem ogromnie rozdętego kodu.  

Marshall Cline wyjaśnia to lepiej niż ja.

Komponent 10
źródło
@Xeo: Kiedyś tak nie było. Sprawdź tutaj: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… Zakładam, że ostatnio się to zmieniło, dlatego mówiłem w czasie przeszłym.
Komponent 10 10
2
@Xeo: Czy możesz wskazać mi część Standardu, w której stwierdza się, że szablony funkcji są zawsze wbudowane? Ponieważ tak nie jest.
Sebastian Mach
@phresnel: Ciekawe, mógłbym przysiąc, że przeczytałem to w standardzie. Może pomyliłem to z faktem, że szablony funkcji są zwolnione z ODR ( §14.5.5.1 p7 & p8). Moja wina, usunąłem zły komentarz.
Xeo
@Component 10 Dlaczego uważasz, że to kiepski sposób na obejście problemu z kompilacją
Kapil