How to properly access the string "bye" from the struct?
#include <iostream>
static constexpr char hi[] = "hi";
struct S{ static constexpr char bye[] = "bye"; };
int main(int argc, char *argv[]) {
typedef struct S ST;
std::cout << hi << std::endl; // this prints "hi"
std::cout << sizeof(ST::bye) << std::endl; // this correctly prints 4
std::cout << ST::bye << std::endl; // this does not compile with "undefined reference"
}
I'm working with a c++ framework that has some configuration in this format (in multiply nested structs even) to make its values available during compile time. I'm not deep enough into C++ to grasp the underlying issue here. Also I cannot argue about why this approach on implementing the configuration was chosen and cannot change it.
This can be made working by redefining the static constexpr outside the struct:
#include <iostream>
static constexpr char hi[] = "hi";
struct S{ static constexpr char bye[] = "bye"; };
constexpr char S::bye[]; // <<< this line was missing
int main(int argc, char *argv[]) {
typedef struct S ST;
std::cout << hi << std::endl; // this prints "hi"
std::cout << sizeof(ST::bye) << std::endl; // this correctly prints 4
std::cout << ST::bye << std::endl; // Now this prints "bye"
}
Or by compiling using c++17 which makes this obsolete.
Related links:
constexpr static member before/after C++17
What does it mean to "ODR-use" something?
Related
What is the meaning of:
typedef uint64_t uint64_t;
I found it in plain source code, not preprocessed one, in the global namespace. Could it simply be a placeholder in case other types should be used in the future?
typedef has the same scope as regular variables in C/C++.
So, it is scoped. In each scope, we could define a new meaning. But, if it has a meaning in that scopy, it cannot be redefined. Also not with the scope operator ::
#include <cstdint>
#include <iostream>
int main() {
{
typedef uint64_t unit64_t;
std::cout << typeid(uint64_t).name() << '\n';
}
{
typedef char uint64_t;
std::cout << typeid(uint64_t).name() << '\n';
typedef uint64_t unit64_t; // Still a char
std::cout << typeid(uint64_t).name() << '\n';
// typedef ::uint64_t unit64_t; // Error
// std::cout << typeid(uint64_t).name() << '\n';
}
{
typedef uint64_t unit64_t;
std::cout << typeid(uint64_t).name() << '\n';
}
return 0;
}
So, I tend to say, that is has no meaning and is a rather academic question.
But I am nearly sure that somebody may find a use case.
i have this piece of code (http://coliru.stacked-crooked.com/a/ee05a00fc8ab5057):
#include <type_traits>
struct unregistered;
unregistered register_type(...);
template<class T>
constexpr bool is_registered = !std::is_same_v<unregistered, decltype(register_type(std::declval<T>()))>;
template<class T>
struct test_registration
{
static_assert(is_registered<T>, "Type is not registered!");
};
struct foo{};
struct bar{};
void register_type(int);
void register_type(char);
void register_type(void*);
void register_type(foo);
void register_type(foo*);
#include <boost/core/demangle.hpp>
#include <iostream>
int main()
{
std::cout << boost::core::demangle(typeid(test_registration<foo>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<foo*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<int>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<char>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<void*>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<long>).name()) << "\n";
std::cout << boost::core::demangle(typeid(test_registration<bar>).name()) << "\n";
return 0;
}
The compiler generates errors for the calls using int, char, void*, long and bar.
I expect the errors for long and bar.
What I do not understand is:
Why are int, char, and foo treated differently?
Why are void*, and foo* treated differently? (both are ptrs)
I assume the reason has to do with foo beeing class type and int and char beeing plain types.
I would like to know the reason. Is it a compiler bug or is there some passage in the standard explaining this behaviour?
What I am asking is not how I can fix this problem (see link to coliru for a fix).
What I want to know is why it is behaving like this.
I show you the code directly.
#include <iostream>
#include <stdio.h>
class A {
public:
A(const std::string& name){
std::string aname = "HAHA_" + name;
std::cout << aname << std::endl;
}
~A(){
std::cout << "Done." << std::endl;
}
};
int main() {
size_t len = 5;
char szTmp[30] ={0};
snprintf(szTmp,sizeof(szTmp),"Getlist_V2_%zd",len);
A a(std::string(szTmp));
return 0;
}
The expected results are as follows:
HAHA_Getlist_V2_5
Done.
But It outputs nothing at all. When I replace A a(std::string(szTmp)); with
A a(szTmp); ,erverything is ok. It confused me for a long time.
A a(std::string(szTmp));
This is a function declaration, believe it or not! So, no A is constructed.
Instead, write this:
A a{std::string(szTmp)};
Or, since an implicit conversion to std::string exists, either of the following will suffice:
A a{szTmp};
A a(szTmp);
Got very weird problem...
I have variable:
Application *ApplicationHandle = NULL;
in Application's function I do:
ApplicationHandle = this;
And ApplicationHandle still remains as NULL... i'm checking this with debugger, before this operation ApplicationHandle is NULL, and 'this' got some address, I can see variables of this class that are valid. After operation ApplicationHandle should be the same pointer as this, but it is still NULL.
How is that possible?
I would suggest moving the static variable out of the global namespace and into the class as a static class member. Here is an example:
// test.hpp
#ifndef TEST_HPP
#define TEST_HPP
class Test
{
public:
// Constructor: Assign this to TestPointer
Test(void) { TestPointer = this; }
// This is just a definition
static Test* TestPointer;
private:
unsigned m_unNormalMemberVariable;
};
#endif /* #ifndef TEST_HPP */
The above code will not work by itself, you need to declare the actual memory of the static member variable (just like you would for a member function).
// test.cpp
#include "test.hpp"
#include <iostream>
// The actual pointer is declared here
Test* Test::TestPointer = NULL;
int main(int argc, char** argv)
{
Test myTest;
std::cout << "Created Test Instance" << std::endl;
std::cout << "myTest Pointer: " << &myTest << std::endl;
std::cout << "Static Member: " << Test::TestPointer << std::endl;
Test myTest2;
std::cout << "Created Second Test Instance" << std::endl;
std::cout << "myTest2 Pointer: " << &myTest2 << std::endl;
std::cout << "Static Member: " << Test::TestPointer << std::endl;
return 0;
}
The static member can be access from any file, not just the file containing the line Test* Test::TestPointer = NULL;. To access the contents of the static pointer, use Test::TestPointer.
Is it possible to make a string as a template parameter and how? Like
A<"Okay"> is a type.
Any string (std::string or c-string) is fine.
Yes, but you need to put it in a variable with external linkage
(or does C++11 remove the requirement for external linkage).
Basically, given:
template <char const* str>
class A { /* ... */ };
this:
extern char const okay[] = "Okay";
A<okay> ...
works. Note thought that it is not the contents of the string
which define uniqueness, but the object itself:
extern char const okay1[] = "Okay";
extern char const okay2[] = "Okay";
Given this, A<okay1> and A<okay2> have different types.
Here's one way to make the string contents determine uniqueness
#include <windows.h> //for Sleep()
#include <iostream>
#include <string>
using namespace std;
template<char... str>
struct TemplateString{
static const int n = sizeof...(str);
string get() const {
char cstr[n+1] = {str...}; //doesn't automatically null terminate, hence n+1 instead of just n
cstr[n] = '\0'; //and our little null terminate
return string(cstr);
}
};
int main(){
TemplateString<'O','k','a','y'> okay;
TemplateString<'N','o','t',' ','o','k','a','y'> notokay;
cout << okay.get() << " vs " << notokay.get() << endl;
cout << "Same class: " << (typeid(okay)==typeid(notokay)) << endl;
Sleep(3000); //Windows & Visual Studio, sry
}