Automatischer Konstruktor in explizit instanziierter Klassenvorlage
Ich habe eintemplate<bool VAR> struct Obj
template deklariert in einer Header-Datei obj.h
) mit explizitem Konstruktor für automatische Verschiebung = default
).
// obj.h
#pragma once
#include <vector>
template<bool VAR>
struct Obj {
std::vector<int> member;
Obj(int m): member(m) { }
Obj(Obj&&) = default;
int member_fun() const;
};
extern template struct Obj<false>;
extern template struct Obj<true>;
Die Mitgliedsfunktion der Vorlage ist in einer anderen Datei definiert obj.cpp
) mit expliziter Instanziierung der Vorlage:
// obj.cpp
#include "obj.h"
template<bool VAR>
int Obj<VAR>::member_fun() const {
return 42;
}
template struct Obj<false>;
template struct Obj<true>;
Diese Vorlage wird dann aus der Hauptdatei verwendet main.cpp
):
// main.cpp
#include <utility>
#include "obj.h"
int main() {
Obj<true> o1(20);
Obj<true> o2(std::move(o1));
return o2.member_fun();
}
Das.cpp
s werden dann kompiliert und mit dem folgenden @ verknüpMakefile
:
#CXX=clang++
CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++14
a.out: obj.o main.o
$(CXX) $(CXXFLAGS) $^ -o a.out
obj.o: obj.cpp obj.h
$(CXX) $(CXXFLAGS) -c #CXX=clang++
CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++14
a.out: obj.o main.o
$(CXX) $(CXXFLAGS) $^ -o a.out
obj.o: obj.cpp obj.h
$(CXX) $(CXXFLAGS) -c $< -o $@
main.o: main.cpp obj.h
$(CXX) $(CXXFLAGS) -c $< -o $@
lt; -o $@
main.o: main.cpp obj.h
$(CXX) $(CXXFLAGS) -c #CXX=clang++
CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++14
a.out: obj.o main.o
$(CXX) $(CXXFLAGS) $^ -o a.out
obj.o: obj.cpp obj.h
$(CXX) $(CXXFLAGS) -c $< -o $@
main.o: main.cpp obj.h
$(CXX) $(CXXFLAGS) -c $< -o $@
lt; -o $@
Ich erhalte jedoch einen Linker-Fehler:undefined reference to 'Obj<true>::Obj(Obj<true>&&)'
- Der Compiler hat den Konstruktor anscheinend nicht instanziiert.
Obj<true>::member_fun()
ist definiert und das Programm verlinkt tatsächlich erfolgreich, wenn ich den Verweis auf den move-Konstruktor von @ entfermain.cpp
.Wenn ich entferneextern template
Aus der Kopfzeile wird das Programm kompiliert.Wenn ich @ benutint
Anstatt vonstd::vector<int>
für den Typ vonmember
, das Programm wird auch kompiliert. cppreference.com behauptet, dass "der Compiler einen move -Konstruktor als nicht explizites @ deklariein der Reih public Mitglied seiner Klasse ". Das manuell definierteObj(int)
er Konstruktor @ ist ebenfalls inline, wird jedoch korrekt instanziiert.(Ich habe diesen Fehler mit Clang in einem Projekt erhalten, das mit GCC einwandfrei kompiliert wurde. Daher dachte ich, dass dies ein Clang-Fehler ist. Als ich das Problem jedoch auf diesen einfachen Fall reduzierte, produzierten sowohl GCC 5.4.0 als auch Clang 3.8.0 das gleiche Ergebnisse.)