clang fails to generate defaulted move constructor upon template instantiation










8















The following code (I couldn't make a shorter MVCE)



unit.h:



#include <vector>

template<typename T>
struct foo

std::vector<T> data;
foo(foo&&) = default; // no assembly generated
foo(std::vector<T>&&v) : data(std::move(v))
;

extern template struct foo<int>; // indicates template instantiation elsewhere


unit.cc:



#include "unit.h"
template struct foo<int>; // forces template intantiation


main.cc:



#include "unit.h"

struct bar

foo<int> f;
bar(foo<int>&&x) : f(std::move(x))
;

bar makeBar(int x)

std::vector<int> v(x);
foo<int> f(std::move(v));
return std::move(f);


int main()

bar x = makeBar(5);



fails to compile under clang (Apple LLVM version 9.0.0 (clang-900.0.39.2) -- which llvm version is that?) with the result:



test> clang++ -std=c++11 -c unit.cc
test> clang++ -std=c++11 -c main.cc
test> clang++ -std=c++11 main.o unit.o
Undefined symbols for architecture x86_64:
"foo<int>::foo(foo<int>&&)", referenced from:
bar::bar(foo<int>&&) in main-476e7b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Everything works fine with gcc (8.2.0). On inspection, it appears that gcc emits foo<int>::foo(foo<int>&&) in main.o, while clang fails to emit it completely.



What is the correct behaviour: should the default move constructor be emitted with unit.o or main.o? Is this a known clang bug?



useful link: https://en.cppreference.com/w/cpp/language/class_template










share|improve this question
























  • Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

    – Matthieu Brucher
    Nov 13 '18 at 14:20















8















The following code (I couldn't make a shorter MVCE)



unit.h:



#include <vector>

template<typename T>
struct foo

std::vector<T> data;
foo(foo&&) = default; // no assembly generated
foo(std::vector<T>&&v) : data(std::move(v))
;

extern template struct foo<int>; // indicates template instantiation elsewhere


unit.cc:



#include "unit.h"
template struct foo<int>; // forces template intantiation


main.cc:



#include "unit.h"

struct bar

foo<int> f;
bar(foo<int>&&x) : f(std::move(x))
;

bar makeBar(int x)

std::vector<int> v(x);
foo<int> f(std::move(v));
return std::move(f);


int main()

bar x = makeBar(5);



fails to compile under clang (Apple LLVM version 9.0.0 (clang-900.0.39.2) -- which llvm version is that?) with the result:



test> clang++ -std=c++11 -c unit.cc
test> clang++ -std=c++11 -c main.cc
test> clang++ -std=c++11 main.o unit.o
Undefined symbols for architecture x86_64:
"foo<int>::foo(foo<int>&&)", referenced from:
bar::bar(foo<int>&&) in main-476e7b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Everything works fine with gcc (8.2.0). On inspection, it appears that gcc emits foo<int>::foo(foo<int>&&) in main.o, while clang fails to emit it completely.



What is the correct behaviour: should the default move constructor be emitted with unit.o or main.o? Is this a known clang bug?



useful link: https://en.cppreference.com/w/cpp/language/class_template










share|improve this question
























  • Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

    – Matthieu Brucher
    Nov 13 '18 at 14:20













8












8








8








The following code (I couldn't make a shorter MVCE)



unit.h:



#include <vector>

template<typename T>
struct foo

std::vector<T> data;
foo(foo&&) = default; // no assembly generated
foo(std::vector<T>&&v) : data(std::move(v))
;

extern template struct foo<int>; // indicates template instantiation elsewhere


unit.cc:



#include "unit.h"
template struct foo<int>; // forces template intantiation


main.cc:



#include "unit.h"

struct bar

foo<int> f;
bar(foo<int>&&x) : f(std::move(x))
;

bar makeBar(int x)

std::vector<int> v(x);
foo<int> f(std::move(v));
return std::move(f);


int main()

bar x = makeBar(5);



fails to compile under clang (Apple LLVM version 9.0.0 (clang-900.0.39.2) -- which llvm version is that?) with the result:



test> clang++ -std=c++11 -c unit.cc
test> clang++ -std=c++11 -c main.cc
test> clang++ -std=c++11 main.o unit.o
Undefined symbols for architecture x86_64:
"foo<int>::foo(foo<int>&&)", referenced from:
bar::bar(foo<int>&&) in main-476e7b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Everything works fine with gcc (8.2.0). On inspection, it appears that gcc emits foo<int>::foo(foo<int>&&) in main.o, while clang fails to emit it completely.



What is the correct behaviour: should the default move constructor be emitted with unit.o or main.o? Is this a known clang bug?



useful link: https://en.cppreference.com/w/cpp/language/class_template










share|improve this question
















The following code (I couldn't make a shorter MVCE)



unit.h:



#include <vector>

template<typename T>
struct foo

std::vector<T> data;
foo(foo&&) = default; // no assembly generated
foo(std::vector<T>&&v) : data(std::move(v))
;

extern template struct foo<int>; // indicates template instantiation elsewhere


unit.cc:



#include "unit.h"
template struct foo<int>; // forces template intantiation


main.cc:



#include "unit.h"

struct bar

foo<int> f;
bar(foo<int>&&x) : f(std::move(x))
;

bar makeBar(int x)

std::vector<int> v(x);
foo<int> f(std::move(v));
return std::move(f);


int main()

bar x = makeBar(5);



fails to compile under clang (Apple LLVM version 9.0.0 (clang-900.0.39.2) -- which llvm version is that?) with the result:



test> clang++ -std=c++11 -c unit.cc
test> clang++ -std=c++11 -c main.cc
test> clang++ -std=c++11 main.o unit.o
Undefined symbols for architecture x86_64:
"foo<int>::foo(foo<int>&&)", referenced from:
bar::bar(foo<int>&&) in main-476e7b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Everything works fine with gcc (8.2.0). On inspection, it appears that gcc emits foo<int>::foo(foo<int>&&) in main.o, while clang fails to emit it completely.



What is the correct behaviour: should the default move constructor be emitted with unit.o or main.o? Is this a known clang bug?



useful link: https://en.cppreference.com/w/cpp/language/class_template







c++ c++11 templates explicit-instantiation template-instantiation






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 6:55







Walter

















asked Nov 13 '18 at 14:17









WalterWalter

27.2k1475153




27.2k1475153












  • Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

    – Matthieu Brucher
    Nov 13 '18 at 14:20

















  • Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

    – Matthieu Brucher
    Nov 13 '18 at 14:20
















Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

– Matthieu Brucher
Nov 13 '18 at 14:20





Latest XCode is 10, so it's probably LLVM 5 or perhaps 6.

– Matthieu Brucher
Nov 13 '18 at 14:20












1 Answer
1






active

oldest

votes


















6














This is a clang bug. Your code is well formed so whatever would be the strategy of the compiler considering the "as if" rule, your code should compile.



Explicit instantiation of a class template only instantiates members for which a definition is provided [temp.explicit]/9:




An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.




Special member function defaulted on their first declaration are only defined when odr-used. So I suppose that the bug is that Clang expects that at the point of explicit instantiation, the defaulted constructor was also instantiated.



So the work around could be first, to declare the move constructor in the header file, then to define it as defaulted in the implementation file:



unit.hpp:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&&)=default;
foo(std::vector<T>&&v) : data(std::move(v))
;
template<T>
foo<T>::foo(foo&&) noexcept;
extern template struct foo<int>;


unit.cpp:



#include <unit.hpp>

template<T>
foo<T>::foo(foo&&) noexcept = default;

template struct foo<int>; //foo(foo&&) has a definition so it is instantiated with the class.


This will force the generation of the definition of the defaulted move constructor (see [dlc.fct.def.default]/5). The draw back is that the definition of foo(foo&&) is not inline anymore.




Alternatively the solution bellow will work:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&& o)noexcept:datamove(o.data);
foo(std::vector<T>&&v) : data(std::move(v))
;





share|improve this answer

























  • It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

    – Walter
    Nov 14 '18 at 6:44











  • Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

    – Walter
    Nov 14 '18 at 6:54











  • @Walter OK I know how to fix that too.

    – Oliv
    Nov 14 '18 at 6:55











  • @Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

    – Oliv
    Nov 14 '18 at 7:04











  • Are you sure? Why do you think clang is wrong?

    – Walter
    Nov 14 '18 at 7:07










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53283030%2fclang-fails-to-generate-defaulted-move-constructor-upon-template-instantiation%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









6














This is a clang bug. Your code is well formed so whatever would be the strategy of the compiler considering the "as if" rule, your code should compile.



Explicit instantiation of a class template only instantiates members for which a definition is provided [temp.explicit]/9:




An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.




Special member function defaulted on their first declaration are only defined when odr-used. So I suppose that the bug is that Clang expects that at the point of explicit instantiation, the defaulted constructor was also instantiated.



So the work around could be first, to declare the move constructor in the header file, then to define it as defaulted in the implementation file:



unit.hpp:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&&)=default;
foo(std::vector<T>&&v) : data(std::move(v))
;
template<T>
foo<T>::foo(foo&&) noexcept;
extern template struct foo<int>;


unit.cpp:



#include <unit.hpp>

template<T>
foo<T>::foo(foo&&) noexcept = default;

template struct foo<int>; //foo(foo&&) has a definition so it is instantiated with the class.


This will force the generation of the definition of the defaulted move constructor (see [dlc.fct.def.default]/5). The draw back is that the definition of foo(foo&&) is not inline anymore.




Alternatively the solution bellow will work:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&& o)noexcept:datamove(o.data);
foo(std::vector<T>&&v) : data(std::move(v))
;





share|improve this answer

























  • It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

    – Walter
    Nov 14 '18 at 6:44











  • Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

    – Walter
    Nov 14 '18 at 6:54











  • @Walter OK I know how to fix that too.

    – Oliv
    Nov 14 '18 at 6:55











  • @Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

    – Oliv
    Nov 14 '18 at 7:04











  • Are you sure? Why do you think clang is wrong?

    – Walter
    Nov 14 '18 at 7:07















6














This is a clang bug. Your code is well formed so whatever would be the strategy of the compiler considering the "as if" rule, your code should compile.



Explicit instantiation of a class template only instantiates members for which a definition is provided [temp.explicit]/9:




An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.




Special member function defaulted on their first declaration are only defined when odr-used. So I suppose that the bug is that Clang expects that at the point of explicit instantiation, the defaulted constructor was also instantiated.



So the work around could be first, to declare the move constructor in the header file, then to define it as defaulted in the implementation file:



unit.hpp:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&&)=default;
foo(std::vector<T>&&v) : data(std::move(v))
;
template<T>
foo<T>::foo(foo&&) noexcept;
extern template struct foo<int>;


unit.cpp:



#include <unit.hpp>

template<T>
foo<T>::foo(foo&&) noexcept = default;

template struct foo<int>; //foo(foo&&) has a definition so it is instantiated with the class.


This will force the generation of the definition of the defaulted move constructor (see [dlc.fct.def.default]/5). The draw back is that the definition of foo(foo&&) is not inline anymore.




Alternatively the solution bellow will work:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&& o)noexcept:datamove(o.data);
foo(std::vector<T>&&v) : data(std::move(v))
;





share|improve this answer

























  • It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

    – Walter
    Nov 14 '18 at 6:44











  • Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

    – Walter
    Nov 14 '18 at 6:54











  • @Walter OK I know how to fix that too.

    – Oliv
    Nov 14 '18 at 6:55











  • @Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

    – Oliv
    Nov 14 '18 at 7:04











  • Are you sure? Why do you think clang is wrong?

    – Walter
    Nov 14 '18 at 7:07













6












6








6







This is a clang bug. Your code is well formed so whatever would be the strategy of the compiler considering the "as if" rule, your code should compile.



Explicit instantiation of a class template only instantiates members for which a definition is provided [temp.explicit]/9:




An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.




Special member function defaulted on their first declaration are only defined when odr-used. So I suppose that the bug is that Clang expects that at the point of explicit instantiation, the defaulted constructor was also instantiated.



So the work around could be first, to declare the move constructor in the header file, then to define it as defaulted in the implementation file:



unit.hpp:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&&)=default;
foo(std::vector<T>&&v) : data(std::move(v))
;
template<T>
foo<T>::foo(foo&&) noexcept;
extern template struct foo<int>;


unit.cpp:



#include <unit.hpp>

template<T>
foo<T>::foo(foo&&) noexcept = default;

template struct foo<int>; //foo(foo&&) has a definition so it is instantiated with the class.


This will force the generation of the definition of the defaulted move constructor (see [dlc.fct.def.default]/5). The draw back is that the definition of foo(foo&&) is not inline anymore.




Alternatively the solution bellow will work:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&& o)noexcept:datamove(o.data);
foo(std::vector<T>&&v) : data(std::move(v))
;





share|improve this answer















This is a clang bug. Your code is well formed so whatever would be the strategy of the compiler considering the "as if" rule, your code should compile.



Explicit instantiation of a class template only instantiates members for which a definition is provided [temp.explicit]/9:




An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.




Special member function defaulted on their first declaration are only defined when odr-used. So I suppose that the bug is that Clang expects that at the point of explicit instantiation, the defaulted constructor was also instantiated.



So the work around could be first, to declare the move constructor in the header file, then to define it as defaulted in the implementation file:



unit.hpp:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&&)=default;
foo(std::vector<T>&&v) : data(std::move(v))
;
template<T>
foo<T>::foo(foo&&) noexcept;
extern template struct foo<int>;


unit.cpp:



#include <unit.hpp>

template<T>
foo<T>::foo(foo&&) noexcept = default;

template struct foo<int>; //foo(foo&&) has a definition so it is instantiated with the class.


This will force the generation of the definition of the defaulted move constructor (see [dlc.fct.def.default]/5). The draw back is that the definition of foo(foo&&) is not inline anymore.




Alternatively the solution bellow will work:



template<typename T>
struct foo

std::vector<T> data;
foo(foo&& o)noexcept:datamove(o.data);
foo(std::vector<T>&&v) : data(std::move(v))
;






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 14 '18 at 10:36

























answered Nov 13 '18 at 15:48









OlivOliv

8,9641957




8,9641957












  • It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

    – Walter
    Nov 14 '18 at 6:44











  • Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

    – Walter
    Nov 14 '18 at 6:54











  • @Walter OK I know how to fix that too.

    – Oliv
    Nov 14 '18 at 6:55











  • @Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

    – Oliv
    Nov 14 '18 at 7:04











  • Are you sure? Why do you think clang is wrong?

    – Walter
    Nov 14 '18 at 7:07

















  • It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

    – Walter
    Nov 14 '18 at 6:44











  • Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

    – Walter
    Nov 14 '18 at 6:54











  • @Walter OK I know how to fix that too.

    – Oliv
    Nov 14 '18 at 6:55











  • @Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

    – Oliv
    Nov 14 '18 at 7:04











  • Are you sure? Why do you think clang is wrong?

    – Walter
    Nov 14 '18 at 7:07
















It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

– Walter
Nov 14 '18 at 6:44





It is indeed a clang bug. I filed a report and learned that it was already fixed in version 6 (apparently w/o a bug report). As to where the explicitly defaulted members are to be exported, I'm still not 100% sure.

– Walter
Nov 14 '18 at 6:44













Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

– Walter
Nov 14 '18 at 6:54





Your workaround works (good), but only provides the (otherwise missing) constructor for the particular instantiation, i.e. for foo<int>. The code will fail to compile with any other foo<T> (very bad). There appears to be no work around, other than avoiding to mix explicitly defaulted member functions with explicit template instantiation.

– Walter
Nov 14 '18 at 6:54













@Walter OK I know how to fix that too.

– Oliv
Nov 14 '18 at 6:55





@Walter OK I know how to fix that too.

– Oliv
Nov 14 '18 at 6:55













@Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

– Oliv
Nov 14 '18 at 7:04





@Walter ... Indeed it work with gcc but not with clang! That is an other bug of clang!

– Oliv
Nov 14 '18 at 7:04













Are you sure? Why do you think clang is wrong?

– Walter
Nov 14 '18 at 7:07





Are you sure? Why do you think clang is wrong?

– Walter
Nov 14 '18 at 7:07

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53283030%2fclang-fails-to-generate-defaulted-move-constructor-upon-template-instantiation%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3

Museum of Modern and Contemporary Art of Trento and Rovereto