I've written this beauty:
#include <iostream>
struct something {
static const char ref[];
};
const char something::ref[] = "";
template<int N, const char(&t_ref)[N], typename to> struct to_literal {
private:
static to hidden[N];
public:
to_literal()
: ref(hidden) {
for(int i = 0; i < N; i++)
hidden[i] = t_ref[i];
}
const to(&ref)[N];
};
template<int N, const char(&ref)[N], typename to> const to* make_literal() {
return to_literal<N, ref, to>().ref;
}
int main() {
const wchar_t* lit = make_literal<sizeof(something::ref), something::ref, wchar_t>();
}
It somewhat cleanly converts between string literal types. But when I compile it, MSVC says that the make_literal function is an undefined external function- which is clearly untrue as it's defined right there.
Edit: I've managed to reduce the problem down without all of the template gunk.
struct some {
friend int main();
private:
static wchar_t hidden[40];
public:
some()
{
}
};
int main() {
std::cout << some::hidden;
//const wchar_t* lit = make_literal<sizeof(something::ref), something::ref, wchar_t>();
}
main.obj : error LNK2001: unresolved external symbol "private: static wchar_t * some::hidden" (?hidden#some##0PA_WA)
It's just a static array. Does life hate me?
The issue is that is that to_literal::hidden is declared but never defined. Take another look:
struct something {
static const char ref[]; // declaration of something::ref
};
const char something::ref[] = ""; // definition of something::ref
template<int N, const char(&t_ref)[N], typename to> struct to_literal {
private:
static to hidden[N]; // declaration of to_literal::hidden (but there's no
// definition anywhere)
public:
to_literal()
: ref(hidden) {
for(int i = 0; i < N; i++)
hidden[i] = t_ref[i];
}
const to(&ref)[N];
};
To fix this, add a proper definition of to_literal::hidden:
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N]; // definition of to_literal::hidden
When you define static members, a declaration does not suffice. You must provide a definition outside the class. I.e. add
wchar_t some::hidden[40];
outside the class, and it'll be defined.
Otherwise, if C++ allowed this, it'd cause the same problem as defining a global variable in a header -- every .cpp file that includes it will come with a duplicate definition, and at link time you'd get a multiply-defined symbol error.
You're declaring but not defining the static member. Add something like...
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N];
I tried to check in MSVC for you too, but with VS2005 I get another stupid error...
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N];
...compiler complains of...
error C3860: template argument list following class template name must list parameters in the order used in template parameter list
Looks like when they fix one bug, there's another one behind it ;-/.
When I built this with VC 2008, that wasn't the error I got. The error was:
Error 1 error LNK2001: unresolved
external symbol "private: static
wchar_t * to_literal<1,&public: static
char const * const
something::ref,wchar_t>::hidden"
(?hidden#?$to_literal#$00$1?ref#something##2QBDB_W##0PA_WA) main.obj Enabler
Removing static from the to hidden[N]; member resolved the issue.
Are you sure you got the error message correct?
Related
Consider the following code:
#include <iostream>
struct FactoryTag
{
static struct Shape {} shape;
static struct Color {} color;
};
template <typename TFactory>
int factoryProducer(TFactory tag)
{
if constexpr (std::is_same<TFactory, FactoryTag::Shape>::value)
return 12;
else if constexpr (std::is_same<TFactory, FactoryTag::Color>::value)
return 1337;
}
int main()
{
std::cout << factoryProducer(FactoryTag::shape) << std::endl;
return 0;
}
It works fine with g++ -std=c++1z Main.cpp but in Visual Studio with MSVC set with c++17 support it gives
Error LNK2001 unresolved external symbol "public: static struct FactoryTag::Shape FactoryTag::shape" (?shape#FactoryTag##2UShape#1#A) StaticTest C:\Users\danielj\source\repos\StaticTest\StaticTest\StaticTest.obj 1
Is this a bug in MSVC?
Is this a bug in MSVC?
No, FactoryTag::shape is odr-used here, so it needs a definition (you're copy-constructing it, which goes through the implicitly generated copy constructor, which requires you to bind a reference). Nor is this a bug in gcc either, arguably, since there is no diagnostic required if a definition is missing.
The solution is to add a definition. The old way would be:
struct FactoryTag { ... };
Shape FactoryTag::shape{}; // somewhere in a source file
The new way would be:
struct FactoryTag {
struct Shape {} static constexpr shape {}; // implicitly inline in C++17
};
I have a header file TimeSeries.h, which has definitions and specializations of default_value template
TimeSeries class has other methods
I included TimeSeries.h file in main.cpp
This is my header file TimeSeries.h, followed by main.cpp
template<typename>
struct default_value;
template<>
struct default_value<int> {
static constexpr int value = 0;
};
template<>
struct default_value<double> {
static constexpr double value = std::numeric_limits<double>::quiet_NaN();
};
template <typename T>
class TimeSeries
{
public:
std::vector<uint64_t> timeUsSinceMid;
std::vector<T> values;
void addValue(uint64_t time, T value)
{
timeUsSinceMid.push_back(time);
values.push_back(value);
}
TimeSeries<T> * sample(uint64_t sampleFreq, uint64_t startTime=0, uint64_t
endTime=86400*1000*1000ULL)
{
//Some code
// I essentially faked a time and a default value push
TimeSeries<T>* newSample = new TimeSeries<T>;
newSample->timeUsSinceMid.push_back(timeUsSinceMid[0]);
newSample->values.push_back(default_value<T>::value);
return newSample;
}
};
Here is main.cpp:
#include<TimeSeries.h>
int main(int argc, const char * argv[]) {
TimeSeries<double> T;
T.addValue(1, 100.0);
T.addValue(2,200.0);
T.addValue(3,300.0);
T.addValue(4,400.0);
TimeSeries<double>* newT = T.sample(2,1,6);
//cout<<*newT<<endl;
return 0;
}
This is the linker error
Undefined symbols for architecture x86_64:
"default_value<double>::value", referenced from:
TimeSeries<double>::sample(unsigned long long, unsigned long long, unsigned long long) in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can anyone please explain why "default_value::value" is undefined?
See the answers for this question.
Using the structure of your posted code
Your template definition defines the object value, but it still needs to be declared.
Don't ask me why, I'm just copying #Pete Becker's answer from the other post (which unfortunately wasn't very detailed). All I know is that the below code now compiles:
template<>
struct default_value<double> {
static constexpr double value = std::numeric_limits<double>::quiet_NaN();
};
// EDIT: inserted line below
constexpr double default_value<double>::value;
Changing the structure a bit
Alternatively, if you don't want to have to track value declarations through a large project, you can also turn the values into in-lined methods, like so: (edit added in constexpr's; also noting that inline is not required & likely doesn't change compiler behavior)
template<>
struct default_value<int> {
// EDIT: changed value to function
static inline constexpr int value() {
return 0;
}
};
template<>
struct default_value<double> {
// EDIT: changed value to function
static inline constexpr double value() {
return std::numeric_limits<double>::quiet_NaN();
}
};
Of course, remember to change your TimeSeries::sample method to use default_value<>::value as a method.
I wrote a code with template copy constructor to get a better understanding of the concept as I am new to it but the following code fails to compile
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Grid
{
public:
explicit Grid(size_t inWidth = kDefaultWidth, size_t inHeight = kDefaultHeight);
virtual ~Grid();
template <typename E>
Grid(const Grid<T>& src);
static const size_t kDefaultWidth = 10;
static const size_t kDefaultHeight = 10;
std::vector<std::vector<T>> mCells;
size_t mWidth, mHeight;
};
template <typename T>
template <typename E>
Grid<T>::Grid(const Grid<T>& src)
{
cout << "Copy constructor working " << endl;
}
int main()
{
Grid<double> myDoubleGrid;
Grid<double> newDoubleGrid(myDoubleGrid);
return 0;
}
On compiling the above code in visual studio following error appears:-
ERROR:-
Severity Code Description Project File Line Suppression State
Error C2558 class 'Grid': no copy constructor available or copy constructor is declared 'explicit'
I have tried to replace the argument's template with E and It shows more errors (strange ones)
template <typename T>
template <typename E>
Grid<T>::Grid(const Grid<E>& src)
{
cout << "Copy constructor working " << endl;
}
Errors:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __thiscall Grid::Grid(unsigned int,unsigned int)" (??0?$Grid#N##QAE#II#Z) referenced in function _main
Error LNK1120 2 unresolved externals
Error LNK2019 unresolved external symbol "public: virtual __thiscall Grid::~Grid(void)" (??1?$Grid#N##UAE#XZ) referenced in function "public: virtual void * __thiscall Grid::`scalar deleting destructor'(unsigned int)" (??_G?$Grid#N##UAEPAXI#Z)
A template constructor is never(!) a copy constructor. The constructor in your code is a converting constructor, only.
You may want both:
#include <iostream>
#include <vector>
// Please do not have this ugliness in a header!
using namespace std;
template <typename T>
class Grid
{
public:
explicit Grid(size_t inWidth = kDefaultWidth, size_t inHeight = kDefaultHeight)
// initialize members ...
{}
// Without this copy-constructor the compiler generates a copy-constructor
// (with no output, of course)
Grid(const Grid& src)
// initialize members ...
{
cout << "Copy constructor" << endl;
}
template <typename E>
Grid(const Grid<E>& src)
// initialize members ...
{
cout << "Converting constructor" << endl;
}
static const size_t kDefaultWidth = 10;
static const size_t kDefaultHeight = 10;
size_t mWidth, mHeight;
};
int main()
{
Grid<double> myDoubleGrid;
Grid<double> newDoubleGrid(myDoubleGrid); // Copy constructor
Grid<int> newIntGrid(myDoubleGrid); // Converting constructor
return 0;
}
See also:
http://en.cppreference.com/w/cpp/language/copy_constructor
http://en.cppreference.com/w/cpp/language/converting_constructor
Derive from template constuctor of template base class
Note that Grid<T>(Grid<U> const&) is not technically a copy constructor, it is a converting constructor. The compiler still generates a copy constructor for you.
The thing to which you call as dangerous error is happening because of your silly mistakes:-
1) You have provided declarations for both constructors and destructors. And as you are saying that it is your one and only source file. It means that you must have not defined them and which is the reason for the linker errors that you are getting. Sometimes these pretty simple problems can prove to be very dangerous and time consuming.
You could have replaced the semicolon with a pair of braces if you don't want to provide any detailed implementation.
2) The thing that you are trying to do is completely logicless as you are creating a converter constuctor with the ssignature similar to copy constructor. Anyway compiler will give preference to copy constructor than your converter constructor.
Ultimately your definition for the constructor will never actually be called.
error LNK2001: unresolved external symbol "public: static int WrappedVector::_N" (?_N#WrappedVector##2HA)
header.h
struct WrappedVector
{
static int _N;
double *_x;
};
main.cpp
const int WrappedVector::_N = 3;
i don't understand whats wrong
Just change the definition
int WrappedVector::_N = 3; // Note no const
see LIVE DEMO1
or the declaration
struct WrappedVector {
static const int _N;
// ^^^^^
double *_x;
};
see LIVE DEMO2
consistently.
If you need the latter form (static const int) you can also initialize it directly in the declaration:
struct WrappedVector {
static const int _N = 3;
// ^^^
double *_x;
};
see LIVE DEMO3
When the following project is compiled, I get the following compiler error: (Visual Studio 2010)
1>usingclass.obj : error LNK2019: unresolved external symbol "public: static int __cdecl c1::arrSize(int * const)" (??$arrSize#H#c1##SAHQAH#Z) referenced in function "public: void __thiscall usingclass::a(void)" (?a#usingclass##QAEXXZ)
Code:
Headers:
c1.h
#pragma once
#include <array>
class c1
{
c1(void);
~c1(void);
public:
template<class T>
static int arrSize(T arr[]);
};
usingclass.h
#pragma once
#include "c1.h"
class usingclass
{
public:
usingclass(void);
~usingclass(void);
void a();
};
Source files:
c1.cpp
#include "c1.h"
c1::c1(void)
{
}
c1::~c1(void)
{
}
template <class T>
int c1::arrSize(T arr[])
{
return (sizeof(arr)/sizeof(arr[0]));
}
usingclass.cpp
#include "usingclass.h"
usingclass::usingclass(void)
{
}
usingclass::~usingclass(void)
{
}
void usingclass::a()
{
int a[2] = {1,2};
int b = c1::arrSize<int>(a);
}
How do I fix that?
Don't do this! The declaration is misleading.
template <class T>
int c1::arrSize(T arr[])
{
return (sizeof(arr)/sizeof(arr[0]));
}
is equivalent to
template <class T>
int c1::arrSize(T *arr)
{
return (sizeof(arr)/sizeof(arr[0]));
}
which will not give you want you want. The proper way to do it is like this:
class c1
{
c1(void);
~c1(void);
public:
template<class T,int N>
static int arrSize(T (&arr)[N]) { return N; }
};
arrSize takes a reference to an array as a parameter. The type of the array and the size of the array are template parameters and can be deduced by the compiler. The inline member function then just returns the size determined by the compiler.
You need to move
template <class T>
int c1::arrSize(T arr[])
{
return (sizeof(arr)/sizeof(arr[0]));
}
inside c1.h.
Template implementations must be visible to all translation units using that template (unless it's specialized, and in your case it's not).
This solves the compiler error but the underlying issue is solved with Vaughn Cato's answer. I missed that. You'll still need the definition in the header.
I think you have to define your template in c1.h itself. Because when you are including c1.h in your usingclass.h, and try to use template it does not find the expansion for template.
Or If you want to go with implementation of template in c1.cpp, then you have to include c1.cpp as well in usingclass.h.