Invalid use of non-static data member for accesing array in a struct - c++

I am trying to work with JUCE Demo, and extract portions of BinaryData.cpp and OpenGLDemo.cpp into my own class. Unfortunately, I run into a problem I can't really parse, which I've managed to reduce in this minimal example of three files: main.cpp, mystuff.cpp and mystuff.h:
main.cpp:
// g++ -std=c++11 main.cpp mystuff.cpp -o main
#include "mystuff.h"
int main(int argc, char* argv[])
{
MyStuff tmpstuff;
std::cout << "hello world" << tmpstuff.temp_binary_data_7[0] << std::endl ;
}
mystuff.h
#include <iostream>
class MyStuff
{
public:
MyStuff();
~MyStuff();
// from BinaryData.cpp:
//~ static const unsigned char temp_binary_data_7[] =
//~ { 35,32,77,97,120,50,79,98,106,32,86,101,114,115,105,111,110,32,52,46,48,32,77,97,114,32,49,48,116,104,44,32,50,48,48,49,10,35,10,35,32,111,98,106,101,99,116,32,84,101,97,112,111,116,48,49,32,116,111,32,99,111,109,101,32,46,46,46,10,35,10,118,32,32,53,
//~ 46,57,50,57,54,56,56,32,52,46,49,50,53,48,48,48,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,56,51,50,48,51,49,32,52,46,52,57,52,49,52,49,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,57,52,53,51,49,51,32,52,46,54,49,55,49,56,56,32,48,46,48,48,48,48,
//~ 48,48,10,118,32,32,54,46,49,55,53,55,56,49,32,52,46,52,57,52,49,52,49,32,48,46,48,48,48,48,48,48,10,118,32,32,54,46,52,50,57,54,56,56,32,52,46,49,50,53,48,48,48,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,51,56,55,49,56,56,32,52,46,49,50,53,48,48,48
//~ };
// move definition to .cpp because of 'error: in-class initialization of static data member ‘const unsigned char MyStuff::temp_binary_data_7 []’ of incomplete type'
static const unsigned char temp_binary_data_7[];
const char* teapot_obj = (const char*) temp_binary_data_7;
// from OpenGLDemo.cpp:
struct Shape
{
Shape()
{
std::cout << "initializing " << static_cast<void*>(teapot_obj) << std::endl ;
}
};
};
mystuff.cpp:
#include "mystuff.h"
const unsigned char MyStuff::temp_binary_data_7[] =
{ 35,32,77,97,120,50,79,98,106,32,86,101,114,115,105,111,110,32,52,46,48,32,77,97,114,32,49,48,116,104,44,32,50,48,48,49,10,35,10,35,32,111,98,106,101,99,116,32,84,101,97,112,111,116,48,49,32,116,111,32,99,111,109,101,32,46,46,46,10,35,10,118,32,32,53,
46,57,50,57,54,56,56,32,52,46,49,50,53,48,48,48,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,56,51,50,48,51,49,32,52,46,52,57,52,49,52,49,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,57,52,53,51,49,51,32,52,46,54,49,55,49,56,56,32,48,46,48,48,48,48,
48,48,10,118,32,32,54,46,49,55,53,55,56,49,32,52,46,52,57,52,49,52,49,32,48,46,48,48,48,48,48,48,10,118,32,32,54,46,52,50,57,54,56,56,32,52,46,49,50,53,48,48,48,32,48,46,48,48,48,48,48,48,10,118,32,32,53,46,51,56,55,49,56,56,32,52,46,49,50,53,48,48,48
};
MyStuff::MyStuff() {
}
MyStuff::~MyStuff() {
}
When I compile with g++, I get this:
$ g++ -std=c++11 main.cpp mystuff.cpp -o main
In file included from main.cpp:3:0:
mystuff.h: In constructor ‘MyStuff::Shape::Shape()’:
mystuff.h:18:42: error: invalid use of non-static data member ‘MyStuff::teapot_obj’
const char* teapot_obj = (const char*) temp_binary_data_7;
^
mystuff.h:25:58: error: from this location
std::cout << "initializing " << static_cast<void*>(teapot_obj) << std::endl ;
^
In file included from mystuff.cpp:1:0:
mystuff.h: In constructor ‘MyStuff::Shape::Shape()’:
mystuff.h:18:42: error: invalid use of non-static data member ‘MyStuff::teapot_obj’
const char* teapot_obj = (const char*) temp_binary_data_7;
^
mystuff.h:25:58: error: from this location
std::cout << "initializing " << static_cast<void*>(teapot_obj) << std::endl ;
^
This happens only when the struct Shape code exists in mystuff.h - if you delete it, then the code compiles and runs fine.
So what are my options? How can I define the struct Shape (or the other variables) so that it can refer to teapot_obj without compilation errors?

Ok, managed to fix it by just throwing expressions here and there, but it would still be great to read an answer that explains what is actually going on... here are my changes - only in mystuff.h:
mystuff.h:
#include <iostream>
class MyStuff
{
public:
MyStuff();
~MyStuff();
static const unsigned char temp_binary_data_7[];
static constexpr const char* teapot_obj = (const char*) temp_binary_data_7;
// from OpenGLDemo.cpp:
struct Shape
{
Shape()
{
std::cout << "initializing " << static_cast<const void*>(teapot_obj) << std::endl ;
}
};
Shape tmptest;
};
So, basically:
const char* teapot_obj = (const char*) temp_binary_data_7;
had to change into:
static constexpr const char* teapot_obj = (const char*) temp_binary_data_7;
... which then means I have to make a static_cast<const void*> (instead of just static_cast<void*>) to print out the object address; and finally, have to add a Shape tmptest; so that the constructor of Shape runs at least once, so we can have something printed.
And now, the program runs without problems:
$ g++ -std=c++11 main.cpp mystuff.cpp -o main
$ ./main
initializing 0x400c60
hello world#

Related

Initializing std::ofstream object in header file v/s source file

I came across some weird compilation error related to std::ofstream. Let's say, I have one header file ofstream_test.hpp, and its corresponding source file ofstream_test.cpp.
ofstream_test.hpp:
#include <iostream>
#include <fstream>
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj("output.txt");
};
ofstream_test.cpp:
#include "ofstream_test.hpp"
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}
main.cpp:
#include "ofstream_test.hpp"
int main(int argc, char const *argv[]) {
OfstreamTest obj;
return 0;
}
The error:
$ g++ -std=c++17 main.cpp ofstream_test.cpp
In file included from main.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
std::ofstream m_strm_obj("output.txt");
^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
std::ofstream m_strm_obj("output.txt");
^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant
If I try to use the open method, I also get the compilation error (a bit different though):
ofstream_test.hpp:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
m_strm_obj.open("output.txt");
};
ofstream_test.cpp:
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}
The error:
$ g++ -std=c++17 main.cpp ofstream_test.cpp
In file included from main.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
m_strm_obj.open("output.txt");
^~~~~~~~~~
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
m_strm_obj.open("output.txt");
^~~~~~~~~~
However, for the following cases, I'm not getting any compilation error:
Case 1:
class OfstreamTest {
public:
OfstreamTest();
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
std::ofstream m_strm_obj("output.txt"); // initialized the object in source file, instead of header file
}
Case 2:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj{"output.txt"}; // just changed () to {}
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
}
Case 3:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj; // declared the object but didn't initialize in the header file
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
m_strm_obj.open("output.txt");
}
I don't understand why?
Would greatly appreciate an in-depth answer (or at least an answer with some reference links)!
std::ofstream m_strm_obj("output.txt"); is invalid syntax when declaring m_strm_obj as a class member (it is fine when declaring it as a local variable).
You simply can't initialize/construct a class data member (regardless of its type) with a value using parenthesis at the point where the member is being declared at class scope. The syntax rules of the C++ standard simply don't allow it, to avoid confusing the compiler with member function declarations.
But, since C++11 onward, you can initialize/construct a class data member at class scope using curly braces instead, eg:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj{"output.txt"};
};
Otherwise, you can instead use the member initializer list of the parent class's constructor, eg:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
};
OfstreamTest::OfstreamTest() : m_strm_obj("output.txt") {
std::cout << "ctor" << std::endl;
}
Or, use open() in the constructor's body, eg:
class OfstreamTest {
public:
OfstreamTest();
std::ofstream m_strm_obj;
};
OfstreamTest::OfstreamTest() {
std::cout << "ctor" << std::endl;
m_strm_obj.open("output.txt");
}

Undefined reference for unoptimised constexpr used as default parameter

I do not understand why the below code compiles with GCC optimised, but fails to link with "undefined reference to `base::A_VAL'" when unoptimised. Am I doing something dodgy? Is this something that's a compiler bug (never is)? This is with g++ 5.4.0 on Ubuntu.
base.h:
class base {
public:
static constexpr unsigned int A_VAL{0x69U};
};
derived.h:
#include "base.h"
#include <iostream>
using namespace std;
class derived : public base
{
public:
int some_func(void) {
cout << "Some func" << endl;
return 0;
}
};
concrete.h:
#include "derived.h"
#include <utility>
class concrete : public derived
{
public:
concrete(int a, std::pair<unsigned int, unsigned int> data = {A_VAL, A_VAL}) {
some_func();
std::cout << "First: " << data.first << " Second: " << data.second << endl;
}
};
test.cpp:
#include "concrete.h"
int main (int argc, char *argv[])
{
concrete c{1};
c.some_func();
}
g++ -O2 -std=c++14 -o test test.cpp
Fine.
g++ -O0 -std=c++14 -o test test.cpp
/tmp/ccm9NjMC.o: In function `main':
test.cpp:(.text+0x23): undefined reference to `base::A_VAL'
test.cpp:(.text+0x28): undefined reference to `base::A_VAL'
collect2: error: ld returned 1 exit status
When optimizing GCC is probably able to determine (after inlining an constant folding) that the body of concrete's constructor can be replaced pretty much by
some_func();
std::cout << "First: " << A_VAL << " Second: " << A_VAL << endl;
Since operator<< for the standard stream class takes integers by value, and A_VAL is a constant expression, the call above doesn't require there to be any storage for A_VAL. Its value is just plugged in. As such, GCC doesn't need there to be an out of class definition for A_VAL, as is normally required for static class members.
When not optimizing, GCC quite likely initializes the pair object. std::pair's constructor takes objects by reference, and a reference requires an object to bind to. So the the definition of A_VAL becomes required and so the linker complains.
You need to define the object somewhere (pre C++17)
// At namespace scope
constexpr unsigned base::A_VAL;
Or switch to compiling as C++17. Then A_VAL (like all constexpr static members data) will be implicitly an inline variable, and the compiler will resolve its definition by itself.
I'm not sure howconstexpr affecting this, but you just declared static class variable, but not defined it. I.e. usually you need to have constexpr unsigned int base::A_VAL{0x69U}; somewhere in .cpp file.

Redefinition of custom delete

I am getting an error saying that I have redefined a function custom_delete.
header.h
#include <iostream>
#include <string>
static int unfreed_count = 0;
#define DELETE(O) custom_delete(O,__PRETTY_FUNCTION__, __LINE__)
void custom_delete(void* ptr, const std::string& function_name, unsigned int line_number) {
unfreed_count--;
std::cout << "delete called in " + function_name + ":" << line_number << std::endl;
std::cout << "unfreed_count: = " << unfreed_count << std::endl << std::endl;
free(ptr);
}
main.cpp
#include "header.h"
int main(int argc, char* argv[]) {
int* ptr = new int;
DELETE(ptr);
}
This code results in the following error message upon attempted compilation:
main.cpp: In function 'void custom_delete(void*, const string&, unsigned int)':
main.cpp:5:6: error: redefinition of 'void custom_delete(void*, const string&, unsigned int)'
void custom_delete(void* ptr, const std::string& function_name, unsigned int line_number) {
^
In file included from main.cpp:21:0:
header.h:7:6: note: 'void custom_delete(void*, const string&, unsigned int)' previously defined here
void custom_delete(void* ptr, const std::string& function_name, unsigned int line_number) {
^
I was trying to make a custom version of delete that printed out when it was used. This was in a larger project, so I made a separate project with just these two files and got the same errors.
I tried commenting out all the code inside the custom_delete function. I also tried writing the prototype before the macro. I got the same error each time.
---EDIT---
I found there was another file being compiled:
header.cpp
#include "header.h"
// Some commented out functions
If I remove the #include "header.h" everything works. However, I eventually will need to add the functions to header.cpp. These functions need stuff that will be added to header.h. What should I do?
It looks like you don't have include guard in your headers.
Add #pragma once as the first line of your header.h
or for more portable solution, add
#ifndef HEADER_H
#define HEADER_H
as first two lines, and
#endif
as last line of the header.h.
Also, to avoid link errors, add inline keyword to declaration of your function, like inline void custom_delete(...
or move function implementation to .cpp.

Linking error with static methods

I'm unable to figure out what's the problem here. I have a ConsoleIO class, which contains two methods:
static void OutputMessage(const std::string &message);
static void OutputMessageNoNewLine(const std::string &message);
They are defined inline in the header:
inline void ConsoleIO::OutputMessage(const std::string &message)
{
std::cout << message << std::endl;
}
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Also another class, ContentParser, with the methods:
static const bool StringEquals(const char *a, const char *b);
template <typename T>
static const std::string NumToString(const T num);
template <typename T>
static const T StringToNum(const std::string &s);
Which are defined in a separate file, ContentParser.cpp.
template <typename T>
const std::string ContentParser::NumToString(const T num)
{
std::ostringstream ss;
ss << num;
return ss.str();
}
I have the following code in the AdventureGame class:
ConsoleIO::OutputMessageNoNewLine(ContentParser::NumToString(num+1));
ConsoleIO::OutputMessage(" - " + decision.choices.at(num).text);
The strange thing is, from the above, the bottom line works fine, but the top produces an error when linking (line 65 error). The StringEquals method also works everywhere.
Here is the build log:
14:03:02 **** Incremental Build of configuration Debug for project AdventureGame ****
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -o AdventureGame.o "..\\AdventureGame.cpp"
g++ "-LD:\\Program Files\\tinyxml2-master" -o AdventureGame.exe tinyxml2.o Main.o ContentParser.o AdventureGame.o -ltinyxml
AdventureGame.o: In function `AdventureGame::ProcessDecision()':
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `std::string const ContentParser::NumToString<unsigned int>(unsigned int)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:68: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
collect2.exe: error: ld returned 1 exit status
What am I missing?
This
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
should be this
inline void ConsoleIO::OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Easy mistake to make.

constexpr different exception specifier when splitting definition and declaration

I have the following test piece of code tested on gcc 4.7.2:
#include <iostream>
#include <type_traits>
#ifdef REMOVE_CONSTEXPR_NOEXCEPT
# define CONSTEXPR_NOEXCEPT
#else
# define CONSTEXPR_NOEXCEPT noexcept
#endif
class ConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static constexpr unsigned int Int(unsigned int i) CONSTEXPR_NOEXCEPT
#ifndef SPLIT_CONSTEXPR_DECLARATION
{
return i;
}
#else
;
#endif
};
#ifdef SPLIT_CONSTEXPR_DECLARATION
constexpr unsigned int ConstExpr::Int(unsigned int i) CONSTEXPR_NOEXCEPT {
return i;
}
#endif
class NoConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static unsigned int Int(unsigned int i) noexcept;
};
// It's OK on normal functions
inline unsigned int NoConstExpr::Int(unsigned int i) noexcept {
return i;
}
int main()
{
std::cout << "ConstExpr: " << std::integral_constant<unsigned int,
ConstExpr::Int(5)>::value << std::endl;
std::cout << "NoConstExpr: " << NoConstExpr::Int(5) << std::endl;
}
I get the following compilation output:
[matt test] g++ -std=c++11 main.cpp && ./a.out
ConstExpr: 5
NoConstExpr: 5
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION && ./a.out
main.cpp:28:55: error: declaration of ‘static constexpr unsigned int ConstExpr::Int(unsigned int)’ has a different exception specifier
main.cpp:17:33: error: from previous declaration ‘static constexpr unsigned int ConstExpr::Int(unsigned int) noexcept (true)’
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION -DREMOVE_CONSTEXPR_NOEXCEPT && ./a.out
ConstExpr: 5
NoConstExpr: 5
So my question is: Is it part of the C++11 spec to be able to split the definition and declaration of constexpr functions or is this a gcc bug?
Looks like the gcc bug solves this in 4.8.1