Constructor automático en plantilla de clase explícitamente instanciada
tengo untemplate<bool VAR> struct Obj
plantilla declarada en un archivo de encabezado (obj.h
) con el constructor de movimiento automático explícito (= 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>;
La función miembro de la plantilla se define en otro archivo (obj.cpp
) con instanciación explícita de la plantilla:
// obj.cpp
#include "obj.h"
template<bool VAR>
int Obj<VAR>::member_fun() const {
return 42;
}
template struct Obj<false>;
template struct Obj<true>;
Esta plantilla se usa desde el archivo principal (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();
}
los.cpp
luego se compilan y se vinculan con lo siguienteMakefile
:
#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 $@
Sin embargo, recibo un error de vinculador:undefined reference to 'Obj<true>::Obj(Obj<true>&&)'
- el compilador aparentemente no creó una instancia del constructor.
Obj<true>::member_fun()
está definido y el programa se vincula con éxito si elimino la referencia al constructor de movimiento demain.cpp
.Si quitoextern template
desde el encabezado, el programa compila.Si yo usoint
en lugar destd::vector<int>
para el tipo demember
, el programa también compila.cppreference.com afirma que "el compilador declarará un constructor de movimiento como no explícitoen línea miembro público de su clase ". Sin embargo, el definido manualmenteObj(int)
El constructor también está en línea, pero está correctamente instanciado.(Recibí este error con Clang en un proyecto que compiló bien con GCC, así que pensé que era un error de Clang. Sin embargo, cuando reduje el problema a este simple caso, tanto GCC 5.4.0 como Clang 3.8.0 producen lo mismo resultados.)