I am trying create a typedef for a template that needs a pointer to member, from within a class. The best way to describe it is to show the minimal sample code:
template<typename T, int T::*MV>
struct Bar
{
const int &value(const T &t) const
{
return (t.*MV);
}
};
struct Foo
{
int baz;
typedef Bar<Foo, &Foo::baz> GetBaz; // Compiler error
};
typedef Bar<Foo, &Foo::baz> GetFooBaz; // Compiles just fine
int main(int argc, char* argv[])
{
Foo f = { 42 };
Foo::GetBaz b; // Fails to compile
GetFooBaz b2; // Fine
int val = b.value(f); // Fails to compile because of above
int val2 = b2.value(f); // Fine
}
I am not necessarily dead-set on getting access to a member pointer in this way, I would be fine just knowing the offset to the variable and having the Bar::value function perform trickery.
As a last resort, I suppose I could use a traits class since the would move the definition outside of the class, but I would prefer to be able to declare the typedef near the variable being used.
And, to answer the "why would you want to do that" question, this is all for an IoC container that closely represents the way MEF (C# works).
The specific compiler I am using is VC12, but it would be nice if VC11 supported it as well.
Thanks
EDIT:
Here are the error messages
1>------ Build started: Project: MemVarBug, Configuration: Debug Win32 ------
1> MemVarBug.cpp
1>memvarbug.cpp(20): error C2327: 'Foo::baz' : is not a type name, static, or enumerator
1>memvarbug.cpp(20): error C2065: 'baz' : undeclared identifier
1>memvarbug.cpp(20): error C2975: 'MV' : invalid template argument for 'Bar', expected compile-time constant expression
1> memvarbug.cpp(7) : see declaration of 'MV'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
you can do the following trick:
declare baz to be int[1];
array of size one, in this case calling baz will return the pointer and calling *baz will return the value.
Related
I am trying to use the automatic differentiation library Adept and I made it work with gcc 4.9.0 and icc 16.0.2 but failed with VS 2017 and Clang 4.0.1
I have reduced the problem to the following snippet and, while I am addressing the issue with the library creators, for the sake of the knowledge I would like to know why this piece of code works in the two mentioned compilers and fails to build in the other two.
template <typename A>
struct Expression
{
static const int rank = A::rank_;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
int main(int argc, char ** argv)
{
return 0;
}
Output for VS 2017 is:
1>------ Build started: Project: Test, Configuration: Debug Win32 ------
1>Source.cpp
1>d:\Test\source.cpp(4): error C2039: 'rank_': is not a member of 'EndIndex'
1>d:\Test\source.cpp(7): note: see declaration of 'EndIndex'
1>d:\Test\source.cpp(8): note: see reference to class template instantiation 'Expression<EndIndex>' being compiled
1>d:\Test\source.cpp(4): error C2065: 'rank_': undeclared identifier
1>d:\Test\source.cpp(4): error C2131: expression did not evaluate to a constant
1>d:\Test\source.cpp(4): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1>d:\Test\source.cpp(4): note: see usage of 'rank_'
1>Done building project "Test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
And output for Clang 4.0.1:
source.cpp:4:37: error: no member named 'rank_' in 'EndIndex'
static const int rank = A::rank_;
~~~^
source.cpp:7:38: note: in instantiation of template class 'Expression<EndIndex>' requested here
struct EndIndex : public Expression<EndIndex>
It probably happens because rank_ is not defined at that stage.
The following fixes it for Apple LLVM version 9.0.0 (clang-900.0.38):
template <typename A>
struct Expression
{
static const int rank;
};
struct EndIndex : public Expression<EndIndex>
{
static const int rank_ = 0;
};
template <typename A>
const int Expression<A>::rank = A::rank_;
Visual C++ and clang are simply unable to find rank_ member of EndIndex because it's being accessed before declared. Such fancy code often leads to problems in some environments.
This question already has answers here:
using c++ aggregate initialization in std::make_shared
(3 answers)
Closed 5 years ago.
I have just started to learn smart pointers
stl::make_unique
Have to change old codes to modern c++
I am getting following error when I compile the below line of code(sample of original code )
#include <memory>
#include <iostream>
using namespace std;
struct Student
{
int id;
float Score;
};
auto main()->int
{
auto Student1 = make_unique<Student>(1, 5.5);
//auto Student1 = make_unique<int>(1); //Works perfectly
//auto Student2 = unique_ptr<Student>{ new Student{1,22.5} }; //Works
cout << "working";
return 0;
}
1>------ Build started: Project: ConsoleApplication4, Configuration: Debug Win32 ------
1>Source.cpp
1>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.10.25017\include\memory(2054): error C2661: 'Student::Student': no overloaded function takes 2 arguments
1>c:\users\hsingh\documents\visual studio 2017\projects\consoleapplication4\consoleapplication4\source.cpp(12): note: see reference to function template instantiation 'std::unique_ptr<Student,std::default_delete<_Ty>> std::make_unique<Student,int,double>(int &&,double &&)' being compiled
1> with
1> [
1> _Ty=Student
1> ]
1>Done building project "ConsoleApplication4.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I tried to look into the make_unique implementation looks like it should have worked .Looked in the above site and possible implementation was
// note: this implementation does not disable this overload for array types
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
so my question is (work around now what i have is to directly use the unique_ptr)
How to make it working using make_unique
What changes I can do to the make_unique implementation in STL so that it works
After few answers
Added question 3
3.What is best using make_unique with constructor or just directly using unique_ptr
unique_ptr<Student>{ new Student{1,22.5} }
I am preferring the later as no need to define constructor .Please do suggest
Unfortunately, make_unique does not perform direct list initialization. If you look into it's description here, you will see following statement:
Constructs a non-array type T. The arguments args are passed to the
constructor of T. This overload only participates in overload
resolution if T is not an array type. The function is equivalent to:
unique_ptr(new T(std::forward(args)...))
Your class doesn't have a constructor which accepts two arguments. It is an aggregate, though, and could be constructed using aggregate initialization, as in your second example:
auto* p = new Student{2, 3};
But make_unique is not calling this form, so this is why it fails. There is a suggestion to make it work like that: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4462.html
Basically, std::make_unique<T> forwards its arguments to the constructor of type T. But there is no constructor in class Student accepting int and double. You might add one:
struct Student
{
Student(int id, float Score) : id(id), Score(Score) {}
int id;
float Score;
};
to make the code work.
template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char>(narrow_str); // error C2040
}
My compiler is VC++ 2013 RC.
The simplest code cannot be compiled because of the error C2040.
error C2040: 'narrow_str' : 'MyString' differs in levels of
indirection from 'char *'
Why?
The problem is this is actually not being parsed as a constructor call but as a variable definition. The problem is you already defined a variable narrow_str. You may have already known this but you can easily fix this by giving it a name.
template<class CharType>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
int main()
{
char* narrow_str = 0;
MyString<char> ns(narrow_str); // error C2040
}
BTW this is also the source of the most vexing parse which occurs when this type of syntax is used in a function argument.
To be honest though I'm surprised that you got a different error because both g++ and clang gave me a clear error.
your syntax in creating a struct is wrong .
change
MyString<char>(narrow_str); // error C2040
to
MyString<char> myString(narrow_str);
will be ok.
include "stdafx.h"
#include <iostream>
using namespace std;
class Foo{
public:
void func()
{
cout<<"Hello!!"<<endl;
}
};
void some_func(const Foo &f)
{
//f.func();
Foo &fr=const_cast<Foo&>(f);
fr.func();
}
int main()
{
some_func(Foo &f); //if const declared will add the no of errors from 2 to 3
return 0;
}
How to invoke the some_func(const Foo &f)...If i declare the const before Foo parameter in main it shows me error...
But if i'm using the code above i'm getting 2 errors..
output:
1>------ Build started: Project: const_cast, Configuration: Debug Win32 ------
1>Compiling...
1>const_cast.cpp
1>c:\documents and settings\beata\my documents\visual studio 2008\projects\const_cast\const_cast\const_cast.cpp(24) : error C2065: 'f' : undeclared identifier
1>c:\documents and settings\beata\my documents\visual studio 2008\projects\const_cast\const_cast\const_cast.cpp(24) : error C2275: 'Foo' : illegal use of this type as an expression
1> c:\documents and settings\beata\my documents\visual studio 2008\projects\const_cast\const_cast\const_cast.cpp(8) : see declaration of 'Foo'
1>Build log was saved at "file://c:\Documents and Settings\beata\My Documents\Visual Studio 2008\Projects\const_cast\const_cast\Debug\BuildLog.htm"
1>const_cast - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Your problem is probably with main()
int main()
{
Foo f;
some_func(f);
return 0;
}
You need to declare f before you can use it.
int main()
{
Foo f;
some_func(f);
return 0;
}
some_func(Foo &f); looks something like a declaration and something like a function call. If you meant a function call you just pass an object of the appropriate type to the function. E.g.
Foo f;
some_func(f);
or if you want to pass an unnamed temporary (legal because the function takes a const reference):
some_func(Foo());
The problen you're seeing is that you haven't labled the func function call as const to indicate to the compiler that it does not modify visible state. That is,
class Foo{
public:
void func() const{
std::cout << "Hello World!" << std::end;
}
};
will work fine. You put the const at the end of the function calls when they do not modify state (not completely true but more advanced for this post.)
So if you want to pass an object by const ref, you will only ever be able to call methods on it that have been declared non-state modifying. Please don't use const_cast unless you absolutely have to.
Also, don't forget to declare a variable of type Foo in your main body.
some_func(Foo &f); //if const declared will add the no of errors from 2 to 3
Wrong syntax.
Here is what you should be doing:
Foo f; //f is an object of type Foo
some_func(f); //pass the object to the function.
I am trying to compile a file which defines a garbage collection template and several supporting classes with use of operator overloading. I've tried to run this through MSVC++ 2008, and the compile stops at this particular class:
// (The collector defines gc_object_generic_base which
// inherits from gc_object_generic_base and optionally adds
// collector-specific properties.)
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
public:
gc_object_base() {
garbage_collector::constructing_gc_object_base(this);
}
static void* operator new(size_t sz,
block_construction_locker_base* lock = block_construction_locker<garbage_collector>().get_this())
{
return garbage_collector::allocate(sz, lock);
}
static void operator delete(void* p, block_construction_locker_base* lock) {
return garbage_collector::deallocate(p);
}
static void operator delete(void* p) {
return garbage_collector::deallocate(p);
}
private:
// TODO: are arrays worth implementing?
static void* operator new[](size_t sz) {
assert(0);
return 0;
}
};
Truncated output for brevity's sake:
2>------ Build started: Project: Test, Configuration: Debug Win32 ------
2>Compiling...
2>FlashTest.cc
2>C:\test\gameswf\base\tu_gc.h(133) : error C2059: syntax error : 'string'
2> C:\test\gameswf\base\tu_gc.h(151) : see reference to class template instantiation 'tu_gc::gc_object_base' being compiled
2>C:\test\gameswf\base\tu_gc.h(135) : error C2091: function returns function
2>C:\test\gameswf\base\tu_gc.h(135) : error C2802: static member 'operator new' has no formal parameters
2>C:\test\gameswf\base\tu_gc.h(135) : error C2333: 'tu_gc::gc_object_base::operator new' : error in function declaration; skipping function body
Any ideas on where I should start looking at?
I just had the same pattern of errors in a different project. It seems to happen when someone has done this somewhere:
#define new new(someArgs, someMoreArgs, etc)
It's targeted at simple 'new' expressions, but it breaks down if anyone tries to declare any more 'operator new' thingies.
In the opening lines
template<class garbage_collector>
class gc_object_base : public garbage_collector::gc_object_collector_base {
garbage_collector appears twice here, once as the template parameter and another as an outer-class to gc_object_collector_base, but as it is a template parameter does it not require "typename" here thus:
template<class garbage_collector>
class gc_object_base : public typename garbage_collector::gc_object_collector_base {
There is no mention of string in your code, that I can see. But I would start by ensuring that you first #include <string> before your class delcaration, and then make sure you use std::string as your declarator, rather than just string.