0

I write a class with template method and use it like below.

#include<string> using namespace std; class A { public: template<typename T> void DoSomething(uint32_t index, T arg); }; template<> void A::DoSomething(uint32_t index,const string &arg) { } void Run(A &a, const string &str) { a.DoSomething(0, str); a.DoSomething<const string &>(0, str); } int main() { A a; Run(a, "HelloWorld"); return 0; } 

This code failed with linker error : undefined reference to `void A::DoSomething<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >(unsigned int, std::__cxx11::basic_string<char, std::char_traits, std::allocator >)

So compiler discards the const reference qualifiers.

Why this happens ? How can fix it ?

11
  • 1
    T is deduced to string in the first example. In general, a by-value parameter will never deduce to a reference. If you want that, the parameter should be const T &, not T. Commented Jan 19, 2023 at 10:10
  • OK, you are right but how to differentiate between call by value and call by const-reference ? Commented Jan 19, 2023 at 10:16
  • 2
    Why do you need this? Templates can't do that. At best you can differentiate const vs non-const and lvalues vs rvalues. Commented Jan 19, 2023 at 10:18
  • 1
    @MohsenTi If I understand this correctly, I would write two functions: const T & and T &&. The first one copies non-persistent objects, the second one std::moves them. For persistent objects, the first one remembers the address, and the other fails with an exceptions. Commented Jan 19, 2023 at 10:50
  • 1
    But the whole idea of persistent vs non-persistent objects looks error-prone to me, but without knowing more about what you do, I can't suggest a better design. Commented Jan 19, 2023 at 10:51

2 Answers 2

1

The problem is that the second parameter arg in DoSomething expects an argument to be passed by value. This means that T is deduced to be std::string and hence the general version of the function template is selected. But since there is no definition for the general version, you get the mentioned linker error.

For example,

template<typename T> //--------vvvvv----------->by value void func(T arg) { } int main() { const std::string str = "name"; func(str); //T is std::string } 
Sign up to request clarification or add additional context in comments.

Comments

0

It's seems the correct answer to this question is perfect forwarding mixed with type traits.

below code shows how PerfectForwardDoSomething method call correct method.

#include<string> #include <vector> #include <type_traits> using namespace std; class DataClass { public: string content; bool isPersist; DataClass(string content, bool isPersist) : content(std::move(content)), isPersist(isPersist) {} }; class A { private: vector<DataClass> keepUntilDestroy; public: template<typename T> void DoSomething(uint32_t index, T arg); template<typename T> void PerfectForwardDoSomething(uint32_t index, T &&arg) { if constexpr (is_reference_v<T>) { DoSomething<const typename decay<T>::type &>(index, std::forward<T>(arg)); } else { DoSomething<T>(index, std::forward<T>(arg)); } } }; template<> void A::DoSomething(uint32_t index, const DataClass &arg) { } template<> void A::DoSomething(uint32_t index, DataClass arg) { keepUntilDestroy.push_back(arg); } void RunRef(A &a, const DataClass &data) { a.PerfectForwardDoSomething(0, data); } void RunVal(A &a, DataClass data) { a.PerfectForwardDoSomething(0, data); } int main() { A a; RunVal(a, {"HelloWorld", false}); RunRef(a, {"HelloWorld2", true}); return 0; } 

5 Comments

And what's with isPersist flag? Ignore it?
Does the DoSomething by pass-by-value actually get used? Mine is only using the DoSomething by pass-by-const-reference.
@HolyBlackCat yes it's not required any more because persistent content call by reference and non-persistent content call by value.
@Eljay, yes it's get call because of explicit instantiate in PerfectForwardDoSomething method.
@MohsenTi • the code does not do that on my machine. I never hit the breakpoint in the one routine.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.