Explicit template specialization for const QString& results in unresolved external - c++

#include <QFile>
#include <QString>
// this is some sort of low-level C function
void lowLevelOpenFD(int fd)
{
qDebug("Opened by fd: %d", fd);
}
// as well as this one
void lowLevelOpenName(const char *name)
{
qDebug("Opened by name: %s", name);
}
// this is a wrapper around low-level functions
template<typename FileId>
void callLowLevelOpen(FileId id);
template<>
void callLowLevelOpen(const QString &fileName)
{
lowLevelOpenName(QFile::encodeName(fileName).constData());
}
template<>
void callLowLevelOpen(int fd)
{
lowLevelOpenFD(fd);
}
// this is the function where the most stuff happens
template<typename FileId>
void openInternal(FileId id)
{
// lots of useful stuff goes here
// now we call one of the two low level functions
callLowLevelOpen(id);
// more useful stuff
}
// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal(name);
}
// this is high-level interface to the "open by FD" function
void openFile(int fd)
{
openInternal(fd);
}
int main()
{
openFile();
openFile(17);
return 0;
}
The problem is that the example above results in
error LNK2019: unresolved external symbol "void __cdecl callLowLevelOpen<class QString>(class QString)" (??$callLowLevelOpen#VQString####YAXVQString###Z) referenced in function "void __cdecl openInternal<class QString>(class QString)" (??$openInternal#VQString####YAXVQString###Z)
As far as I can see it happens because the compiler instantiates openInternal<QString>() when it's called from the first high-level overload. OK, so I thought and modified the code:
// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal<const QString&>(name);
}
The same problem. And I thought I told the compiler to instantiate the openInternal<const QString&>, so why it is still complains about <class QString>? I also tried this one:
// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal<const QString&>(static_cast<const QString&>(name));
}
Now this just looks silly and it still doesn't work. I can't explicitly specialize the openInternal() one because it's too large and the very point of this templated mess is to avoid unnecessary code duplication. I can't just rename the low level functions to turn them into overloaded ones, because they are in a third-party C library. The only thing I can do is to replace the first callLowLevelOpen() specialization with
template<>
void callLowLevelOpen(QString fileName)
{
lowLevelOpenName(QFile::encodeName(fileName).constData());
}
Then it works. There is also virtually zero performance penalty so this is a perfectly valid workaround, but I just want to understand what is going on here.
The code above was just an SSCCE, the real code is there if anyone interested. This particular issue is with the gzopen()/gzdopen(), QuaGzipFilePrivate::open() and QuaGzipFile::open() functions.

Since you actually change the signature, I think you actually don't want to specialize your function template but rather use overloading. Here is complete test program using std::string (I somehow prefer depending only on standard classes if the problem can be reproduced there as well):
#include <string>
template <typename T> void f(T);
// #define BROKEN
#if defined(BROKEN)
template <> void f(std::string const&) {}
#else
void f(std::string const&) {}
#endif
int main()
{
std::string s;
f(s);
}
If you #defined BROKEN in this code it won't work.
The reason for this behavior is that the compiler choose the overload based on the primary template. This will never add the const& part. Once this is done the compiler looks for potential specializations of the chosen overload. Since this will never have deduced the notation used for specialization this isn't picked up.
Why then is the f<std::string const&>(s) not picking up the specialization? For me it is, trying with both gcc and clang.

Related

Compiler/linker complaining about function definition not found in C++

I've done this so many times, yet the reason why Visual Studio is complaining about this escapes me.
Manipulator.cpp:
#include "Manipulator.h"
Manipulator::Manipulator() {}
Manipulator::~Manipulator() {}
void proc(std::string p, int f, std::string c)
{
// switch-case p to c based on f:
return;
}
Manipulator.h: (void -proc- has a curly underscore, and that's what's driving me up the wall.)
#ifndef MANIPULATOR_H
#define MANIPULATOR_H
#include <string>
class Manipulator
{
private:
protected:
public:
Manipulator() ;
~Manipulator() ;
void proc(std::string, int, std::string);
// function definition for 'proc' not found.
};
#endif MANIPULATOR_H
main.cpp
#include "Manipulator.h"
...
int main()
{
...
Manipulator m;
...
m.proc(opdBMP, fxn, newBMP);
return 0;
}
What is it that VS wants so that I can get a move on? It is telling me that there are two linker errors: LNK2019 and LNK1120 (unresolved external). (I used to keep track of these kinds of errors but lost the file as a log with these.)
The compiler is correct in complaining, because the definition should be
void Manipulator::proc(std::string p, int f, std::string c) {
...
}
You just defined a free function instead of a member of Manipulator.

extern declared template specialized function not found

i'm trying to implement a clone of the json serialization library nlohmann::json as a learning experience, and i'm having trouble with the interface for user defined (json<->User type) conversion.
Basically i want the user to be able to overload two function: to_json(json&, const Type&) and from_json(const json&, Type&). Then the library will use overload resolution to call theses function in the templated operator= and one argument constructor.
It works fine when i'm just defining theses function directly but when i try to make a template definition for multiple types (in this example the class S) the linker can't find the definition.
I've tried to explicitly instantiate the function for individual instances of the templated class although i would prefer avoiding having to do that in the final product.
I'm guessing it has to do with the fact that templated function don't have the same signature than free function, but i don't see what i can do to make it work. What am i missing ? I also couldn't find result on google so is it a documented pattern or an anti pattern ?
Thanks you. Below i tried to minimize my problem in one short example.
Class.hpp
#pragma once
#include <cstdio>
template<size_t i>
class S {
size_t n = i;
};
template<size_t i>
void g(const S<i>& s) {
printf("S<%u>\n", i);
}
Class.cpp
#include "Class.hpp"
template void g<10>(const S<10>&); // <-- Even with explicitly instanciation
void g(const bool& b) {
printf("%s\n", b ? "true" : "false");
}
main.cpp
#include "Class.hpp"
template<typename T>
void f(T t) {
extern void g(const T&);
g(t);
}
int main(int, char**) {
S<10> s;
//f(s); <-- linker error: void g(class S<10> const &) not found.
f(false);
}
The name lookup for g in g(t) call stops as soon as it finds extern void g(const T&); declaration; it never sees the declaration of the function template. So the compiler generates a call to a regular non-template function named g taking const S<10>&. But no such function is defined in your program - hence linker error.

Why does inlining my accessors break my code?

I am experiencing a strange issue where attempting to inline the accessors for my "Person" class causes the code to fail to compile.
The following code will compile and run successfully (Using Visual Studio 2012):
Person.h
#pragma once
#include <string>
using namespace std;
class Person
{
public:
Person(string name, int age = 0);
~Person(void);
// Accessors
string name(void) const;
int age (void) const;
private:
string m_name;
int m_age;
};
Person.cpp
#include "stdafx.h"
#include "Person.h"
Person::Person(string name, int age) :
m_name(name),
m_age (age )
{}
Person::~Person(void) {}
string Person::name(void) const
{
return m_name;
}
int Person::age(void) const
{
return m_age;
}
header_test.cpp
#include "stdafx.h"
#include <iostream>
#include "Person.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Person p("Joe");
cout << p.name() << endl;
return 0;
}
If I change my accessors to be defined as inline functions the code breaks.
Inlining the accessors in Person.h
// Accessors
inline string name(void) const;
inline int age (void) const;
Inlining the accessors in Person.cpp
inline string Person::name(void) const
{
return m_name;
}
inline int Person::age(void) const
{
return m_age;
}
Doing this produces the following errors:
1>header_test.obj : error LNK2019: unresolved external symbol "public: class std::basic_string,class std::allocator > __thiscall Person::name(void)const " (?name#Person##QBE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) referenced in function _wmain
1>fatal error LNK1120: 1 unresolved externals
God that error message is cryptic... Thank you for all of that oh so useful information Microsoft/Visual Studio!
I know the inline keyword is just a "hint" to the compiler and probably has no real value here, but it still shouldn't break the code!
Why is this happening?
I am not a language lawyer, so I can't tell if the compiler behaviour is legitimate or not. Yet, I can explain what is happening.
When you are marking your functions inline, you are not hinting the compiler that it can inline this function. Since over 10 years compilers do not need your hint here. They know when to inline. Instead, what you do, you indicate the function definition to be local for every translation unit it is included in. For this definition should be available.
Effectively what you said is that name() definition should be local for every .cpp file, but you didn't make it available for every .cpp file! I still believe the compiler could give a warning here.
You need to define the function body in the header if you want to use the inline keyword. inline also does more than just give a hint to the compiler: it more or less shuts down the "one definition" rule* about functions being defined once and only once.
Furthermore, if you define class member functions inside the headers, ala
class Foo {
int bar() { return 5; }
};
they get "inlined" by default, so there's no reason to type the keyword out :-)
* Technically not, but for simplicity you can think of it as behaving that way. See the comment below by SergeyA.

Overload for undefined type

I am trying to do some overload on the template function, following are the examples
do_something.h
template<typename T>
void do_something(T const &input){/*....*/}
void do_something(std::string const &input);
void do_something(boost::container::string const &input);
so far, so good, but what if I want to overload a non-defined type?
like using a type some_type have not defined in the header file
void do_something(some_type const &input);
I want to use it like this
main.cpp
#include "do_something.h"
#include "some_type.h"
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}
Since some_type is not a POD, not a std::string, boost::container::string.I guess I could designed a traits to do some compile time checking
template<typename T>
typename boost::enable_if<is_some_type<T>::value, T>::type
do_something(T const &input){//.....}
But do I have a better way to do it?
I need compile time type checking, so I use template.All of the types calling this function will do similar jobs based on different types, so I prefer overload.I do not need to save the state, so I prefer function rather than class.
Hope this could help you know more about what I intent to do.Thank you
but what if I want to overload a non-defined type?
You need to provide the declaration of
void do_something(some_type const &input);
before you call do_something with an object of type some_type. Otherwise, the template version will be used.
#include "do_something.h"
#include "some_type.h"
// This is all you need. You can implement the function here
// or any other place of your choice.
void do_something(some_type const &input);
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}

Setting a calling convention for std::function

I'm very new to using std and I'm currently trying to call into a function that takes an std::function as a param. Something similar to below:
In the .h file in one lib:
typedef bool t (/*Params*/);
void __stdcall Foo(std::function<t> &function) {m_function = function;}
std::function<t> m_function;
I imported the lib and tried to use Foo in another cpp file:
bool Implementation (/*Params*/)
{
// Implementation
}
void Bar()
{
Foo(std::function<t> (Implementation));
}
I'm getting a linker error (LNK2019) when I compile for x86 (but not x64) because of the calling convention:
Unresolved External Symbol __stdcall Foo (class std::tr1::function<bool __cdecl(/*Params*/) const&)
From this I gathered that I need to mark "t" and Implementation as __stdcall but doing so causes other compile failures. I should also note the code compiled correctly when it was being built in the same lib. Is there a way to associate a calling convention to an std::function?
Try:
void Foo(const std::function<bool()> &func)
{
func();
}
bool Implementation (/*Params*/)
{
cout << "Implementation"<<endl;
return true;
}
void Bar()
{
Foo(std::function<bool()>(&Implementation));
}
int main()
{
Bar();
return 0;
}