I get the following base error:
1>c:\program files\microsoft visual studio 10.0\vc\include\utility(163): error C2436: 'second' : member function or nested class in constructor initializer list
As well as a lot of sub-errors there - I have no idea at all where to look or what goes wrong. (I know what functions it is about, but I'm staring myself blind on why it doesn't work)
The header part:
typedef void *DuplicateFn(pTree&, const pTree&);
enum DuplicateTy {
SKIP,
OVERWRITE,
ASK
};
typedef std::map<DuplicateTy, DuplicateFn> DuplicateMapTy;
static const DuplicateMapTy DuplicateFns;
static DuplicateMapTy DuplicateFns_INIT();
detail namespace:
namespace detail {
void OverWriteFn(GMProject::pTree& tOut, const GMProject::pTree& tIn);
void AskFn(GMProject::pTree& tOut, const GMProject::pTree& tIn);
}
The source part:
GMProject::DuplicateMapTy GMProject::DuplicateFns_INIT() {
DuplicateMapTy tmp;
auto p(std::make_pair(GMProject::OVERWRITE, &detail::OverWriteFn));
tmp.insert(p); //offending line
return tmp;
}
const GMProject::DuplicateMapTy GMProject::DuplicateFns(GMProject::DuplicateFns_INIT());
As said I'm staring myself blind on this, why can't I insert that pair into the map? I'm simply inserting a function pointer & an enum?
I might be wrong, but I don't like the line:
auto p(std::make_pair(GMProject::OVERWRITE, &detail::OverWriteFn));
Are you using VS 2010? You can hover the variable name (p) and see which type auto has deduced.
Also, have you tried:
tmp.insert(std::make_pair(GMProject::OVERWRITE, &detail::OverWriteFn));
Or
tmp.insert(std::pair(GMProject::OVERWRITE, &detail::OverWriteFn));
?
Related
I'm wracking my brain here for several hours, but I still don't understand why I'm getting an error when I'm trying to run this code.
After some time I managed to narrow it down to the expression:
pastryPrice()
which causes the problem - as you can see, I'm trying to build numerous comparators for one template function of sorting
struct dialingAreaComp{
inline bool operator()(const Deliver *d1, const Deliver *d2)const {
return d1->getDialingArea() < d2->getDialingArea();
}
};
struct pastryPrice {
inline bool operator()(const Pastry *p1, const Pastry *p2)const {
return p1->getPrice() < p2->getPrice();
}
};
template<class T>
void sortCollection(T& collection)
{
if ( typeid (collection) == typeid(vector <Deliver*>))
{
sort(collection.begin(), collection.end(), dialingAreaComp());
printCollection(collection);
}
else if (typeid (collection) == typeid(vector <Pastry*>))
{
sort(collection.begin(), collection.end(), pastryPrice());
printCollection(collection);
}
else { cout << "WRONG!"; }
}
I'm getting five errors, all the same:
Severity Code Description Project File Line Suppression State
Error C2664 'bool Bakery::pastryPrice::operator ()(const Pastry *,const Pastry *) const': cannot convert argument 1 from 'Deliver *' to 'const Pastry *' Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
And one more:
Severity Code Description Project File Line Suppression State
Error C2056 illegal expression Bakery c:\program files (x86)\microsoft visual studio 14.0\vc\include\xutility 809
When I take off the expression I wrote above, the code works just fine - why can't I pass two different comparators to one template function?
Now:
C2264 is a Compiler Error that occurs when one tries to pass a function a parameter of an incompatible type.
But the Deliver function works and when I took off the Deliver comparator the Pastry compiled as well... so what is the incompatible type?
Your problem is both branches are compiled regardless of which one is taken.
I would approach this differently.
template<class A, class B>
struct overload_t:A,B{
using A::operator();
using B::operator();
overload_t(A a, B b):A(std::move(a)), B(std::move(b)){}
};
template<class A, class B>
overload_t<A,B> overload( A a, B b ){
return {std::move(a),std::move(b)};
}
This lets us overload two function objects or lambdas. (Perfect forwarding could be added, as can varargs..., but I kept it simple).
Now we simply:
auto comp=overload(dialingAreaComp{}, pastryPrice{});
using std::begin; using std::end;
std::sort( begin(collection), end(collection), comp );
and the compiler chooses the correct comparison function for us. Also flat array support while I was in there.
And stop using using namespace std;.
What the above code does is fuze your two function object tyoes into one. The using A::operator() and using B::operator() moves both () into the same class and tells C++ to pick between them when invoked using the usual method call overloading rules. The rest of the code is glue to deduce the types being overloaded and move-construct them.
sort calls () with objects of the compile-time determined type based on the type of the container. Overload resolution (within sort at the point of call) then picks the right body to compare at compile time.
Thus technique can be extended with support for more than 2 overloads, function pointers, and forwarding references. In C++17 some work can be done to have the overload type deduce its parent types, removing the need for the factory function.
You get an error because the templated function is evaluated at compile time, and one of the function calls will never match. Instead of the template use simple function overloads:
void sortCollection(vector <Deliver*>& collection)
{
sort(collection.begin(), collection.end(), dialingAreaComp());
printCollection(collection);
}
void sortCollection(vector <Pastry*>& collection)
{
sort(collection.begin(), collection.end(), pastryPrice());
printCollection(collection);
}
I'm trying to type alias the std::bitset class where the template parameter N is calculated using a constexpr function. However, this approach seems to be running into a wall.
The code currently looks like this:
static constexpr std::size_t ComponentCount() noexcept {
return 3U;
}
static constexpr std::size_t TagCount() noexcept {
return 5U;
}
using Bitset = std::bitset<ComponentCount() + TagCount()>;
And the error I'm receiving is as follows:
1>error C2975: '_Bits': invalid template argument for 'std::bitset', expected compile-time constant expression
1> note: see declaration of '_Bits'
Thanks for your help.
As indicated in the comments by #MattWeber, using the current webcompiler.cloudapp.net with compiler version 19.00.23720.0 (built 20 January 2016) this small test program using your code
int main()
{
cout << Bitset{}.size() << "\n";
}
does output 8. So just grab the latest Visual Studio and check the compiler version (if it's greater than 19.00.23720.0 it should work).
As things turned out, I didn't include enough context in my original question. The problem ended up being a little more subtle.
Here's a more accurate representation of how my code looked:
template
<
typename ComponentList,
typename TagList,
typename SignatureList
>
struct Settings {
// ...
static constexpr std::size_t ComponentCount() noexcept {
return 3U;
}
static constexpr std::size_t TagCount() noexcept {
return 5U;
}
// ...
using Bitset = std::bitset<ComponentCount() + TagCount()>;
// ...
};
This approach seemed okay to me, and didn't provide me with any compiler warnings or anything. Just the compiler error mentioned in the original question.
However, when I simplified the problem further in an attempt to more accurately isolate the problem, I ended up with this:
struct Settings {
static constexpr std::size_t ComponentCount() noexcept {
return 3U;
}
static constexpr std::size_t TagCount() noexcept {
return 5U;
}
using Bitset = std::bitset<ComponentCount() + TagCount()>;
};
After doing this simplification (or more specifically, after removing the template parameters), VS2015 found the the error function call must have a constant value in a constant expression on both of the ComponentCount() and TagCount() function calls, and highlighted them in red. Apparently the compiler is unable to view static constexpr functions that are contained within the same struct as constant expressions? Weird. It might be trying to do the type aliasing before defining the const expressions.
The solution for the templated struct was as follows:
using ThisType = Settings<ComponentList, TagList, SignatureList>;
// ...
using Bitset = std::bitset<ThisType::ComponentCount() + ThisType::TagCount()>;
However, this approach doesn't work for the non-templated struct. See my other StackOverflow post for different approaches in that case.
This question already has answers here:
C/C++ changing the value of a const
(18 answers)
Closed 8 years ago.
I have a struct which is defined in types.h with the following code:
struct data_Variant {
FlightPlanSteeringDataRecord steeringData;
FlightPlanType flightPlan : 8;
MinitoteLegDataType legDataType : 8; // discriminent, either current or amplified
unsigned spare : 16;
union {
// currentLeg =>
CurrentLegDataRecord currentLegData;
// amplifiedLeg =>
AmplifiedLegDataRecord amplifiedLegData;
} u;
};
I am then trying to pass an instance of that struct as a parameter to a function in a C++ source file called dialogue.cpp:
void dialogue::update( const types::data_Variant& perfData){
...
}
I now want to change the value of some of the members of that struct inside this update() function. However, if I try doing this as I usually would, i.e.
perfData.etaValid = true;
I get a compile error which says: "C2166: l-value specifies const object". As I understand, this is because perfData has been declared as a constant variable. Am I correct in thinking this?
Since I didn't write this part of the code, but only want to use it to update the value displayed on the GUI, I don't really want to change the perfData variable by removing the const keyword, in case I break something else. Is there any way to change the value of a variable that has been declared as const?
I have tried declaring the same struct variable in another part of the code, without using the const keyword, to see if I can change the values of some of its members there... i.e. in Interface.cpp, I have added the following code to a function called sendData():
types::data_Variant& perfData;
perfData.steering.etaValid = true;
perfData.steering.ttgValid = true;
However, I now get the following compile errors on these lines:
error C2653: 'types' is not a class or namespace name
error C2065: data_Variant: undeclared identifier
error C2065: 'perfData': undeclared identifier
error C2228: left of '.steering' must have class/ struct/ union
Is there a way of updating the values of this struct? If so, how should I do it, and what am I doing wrong here?
I have added the following function to the dialogue.cpp source file, as suggested in the answer:
void dialogue::setFPTTGandETAValidityTrue(
FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant& perfData)
{
SESL_FUNCTION_BEGIN(setFPTTGandETAValidityTrue)
perfData.steeringData.fpETAValid = true;
perfData.steeringData.fpTTGValid = true;
SESL_FUNCTION_END()
}
You could add a wrapper for yourself.
void myupdate(dialogue& dia, types::data_Variant& perfData)
{
perfData.etaValid = true;
dia.update(perfData);
}
Then call myupdate() instead of dialogue::update().
You declare
void dialogue::update( const types::data_Variant& perfData){
...
}
that const is a declaration of you saying: "I won't modify the referenced object in this function". If you want to modify it in dialogue::update you have to remove the const keyword. Wrapping is not a solution, in my opinion, makes the code harder to maintain. Also I vote against remove const with const_cast.
The correct solution is to remove const from method declaration if you want to modify the referenced object inside that function.
I have a struct defined as:
template<typename T>
struct unique_owned_item_filter: public std::unary_function<T,bool> {
unique_owned_item_filter(){}
bool operator()(const T& item)const {
return !item->shared() || item->owner() == MPI::COMM_WORLD.Get_rank();
}
typedef T item_type;
};
and I want to use this structure in a function like this
void read_nodes(std::ifstream& infile, mesh_type& mesh, const std::list<int>&my_nodes)
{
typedef typename mesh_type::node_t nd_t;
..... follows some code .....
create_double_nodes(mesh,unique_owned_item_filter<nd_t>);
}
where the function create_double_nodes is defined as
template<typename mesh_type, typename rule_type >
void create_double_nodes(mesh_type& mesh,rule_type& rule){
.... follows some code ....
}
When I pass to create_double_nodes the argument unique_owned_item_filter I insert
its dependence on the template parameter nd_t, that, in my case, is the mesh node
of type mesh_type::node_t.
When I compile the whole, I get the error expected primary-expression before ')' token at the declaration of create_double_nodes(mesh,unique_owned_item_filter<nd_t>);.
It seems to me that the template argument is right.
Can somebody help me?
The problem in the definition of the create_double_nodes disappeared, but now the problem appeared inside the body of the function itself.
template<typename mesh_type, typename rule_type >
void create_double_nodes(mesh_type& mesh, const rule_type& rule){
typename mesh_type::nd_set_t::const_iterator it_first( mesh.nodes().begin());
while(it_first!=mesh.nodes().end()){
if(rule(*it_first))
....follows code ....
it_first++
}
when i apply the rule to the const iterator it does not accept it. The compilation gives the following error:
no match for call to '(const GALES::unique_owned_item_filter, 5, GALES::base_5_dofs> >) (GALES::fem_node, 5, GALES::base_5_dofs>* const&)'
with candidates
bool GALES::unique_owned_item_filter<T>::operator()(const T&) const [with T = GALES::fem_node<GALES::geometric_node<2>, 5, GALES::base_5_dofs>]
where
GALES::fem_node<GALES::geometric_node<2>, 5, GALES::base_5_dofs>
is the complete type of node of the mesh.
I cannot understand why the rule applied to a constant iterator is not accepted. If you need more details I will try to explain it better.
Thank you very much again.
unique_owned_item_filter<nd_t> is a type, but you're using it as a function argument, where a value is required. You probably wanted to create an object of this type instead:
create_double_nodes(mesh, unique_owned_item_filter<nd_t>());
// ^^ parens here!
This will not work as-is, though, because your function template create_double_nodes takes the second parameter by non-const reference, and such cannot bind to a temporary (such as the one created in my example above).
You have two solutions: either change create_double_nodes to take its parameter by const-reference, or create a named object for the argument:
unique_owned_item_filter<nd_t> filter;
create_double_nodes(mesh, filter);
1.Make it an object:
create_double_nodes(mesh,unique_owned_item_filter<nd_t>());
^^
2.Pass by const reference or value:
void create_double_nodes(mesh_type& mesh, const rule_type& rule){
^^^^^
I don't think my question is a duplicate of this one.
what I try to do:
template<const char* szFunctionName>
class CReentranceLock
{
public:
CReentranceLock(){}
~CReentranceLock(){}
bool isLocked(){return s_bLock;}
void setLocked(bool b)
{
const bool Result=(bool)InterlockedCompareExchange(
(unsigned long *)&s_bLock, b, !b);
}
private:
static bool s_bLock;
};
template<const char* szFunctionName>
bool CReentranceLock<const char*szFunctionName>::s_bLock=false;
// error C2146: syntax error : missing ',' before identifier 'szFunctionName'
implying that all instances of CReentranceLock would have their own static, relying on the const char address of the function name passed as a parameter of the template.
and that could be used like this:
void CMyObject::InAnyFunction()
{
const char* szFunctionName = __FUNCTION__;
CReentranceLock<szFunctionName> lock; // Edit: <- this doesn't work
if(lock.isLocked()) return;
lock.setLocked(true);
/// business code
lock.setLocked(false);
}
well that's only the theory...
and unfortunately this doesn't compile under visual 2010, at the line where I try to initialize the statics.
error C2146: syntax error : missing ',' before identifier 'szFunctionName'
what am I doing or thinking wrong ?
PS: and I am not dealing with the fact that reentrance is smelling like an awful design (in MFC), I know, I am lost in the middle of it ;-)
Edit: though the answer below is good, and the definition compiles... my use in CMyObject::InAnyFunction() with a const char * as a template-parameter available at compile time seems to be wrong. :-(
bool CReentranceLock<const char*szFunctionName>::s_bLock=false;
This should be:
bool CReentranceLock<szFunctionName>::s_bLock=false;
Just change the line to
bool CReentranceLock<szFunctionName>::s_bLock=false;