Strange compilation error

Hi,
In the example below, I use 2 "dummy" classes (LoKey and HiKey) to choose between 2 constructors in MyKey class. This works very fine except in the last test-funktion.

Compiling with MS Visual C++ 2019 I get the following compilation error:
error C2664: 'void test(MyKey)': cannot convert argument 1 from 'MyKey (__cdecl *)(LoKey (__cdecl *)(void))' to 'MyKey'.

Compiling and running the program without the line "test(k3)" works fine.
I've tried with several online compilers such as "C++ Shell" and "https://www.jdoodle.com/online-compiler-c++". They all complain complain the same issue.

So I guess it's not a compiler error, but I just cannot understand why there is a problem.
Can anyone help me on this?

Kind regards
Henrik T.


#include <iostream>
#include <string>

class LoKey {};
class HiKey {};

class MyKey
{
public:
MyKey(LoKey, int i = -1, int j=-1) : i_(i), j_(j) {}
MyKey(HiKey, int i = 100, int j=999) : i_(i), j_(j) {}
int i_,j_;
};

void test(MyKey k)
{
std::cout << "I-Value=" << k.i_ << std::endl;
}

int main()
{
LoKey lokey;
MyKey k1(lokey);
test(k1);
MyKey k2(LoKey(),33);
test(k2);
MyKey k3(LoKey());
//test(k3); /* This line produces compilation error */
}
Last edited on
closed account (z05DSL3A)
Quick look:

I think the line MyKey k3(LoKey()); is confusing the compiler, you could try MyKey k3(LoKey{}); instead.
 
MyKey k3(LoKey());


:) :) Sorry for the smile. You have fallen victim to the most vexing parse in c/c++!

This does not do what you think it does. This is actually a function declaration statement for the function k3, returning a type MyKey with a parameter of LoKey.

You need:

 
	MyKey k3((LoKey()));


Note the extra sets of brackets. This is now an invalid function declaration so the compiler then tries it as a variable definition. c/c++ compiler always first tries to parse as a function declaration and only if that parse fails does it try others.

This now compiles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>

class LoKey {};
class HiKey {};

class MyKey
{
public:
	MyKey(LoKey, int i = -1, int j = -1) : i_(i), j_(j) {}
	MyKey(HiKey, int i = 100, int j = 999) : i_(i), j_(j) {}
	int i_, j_;
};

void test(MyKey k)
{
	std::cout << "I-Value=" << k.i_ << std::endl;
}

int main()
{
	LoKey lokey;
	MyKey k1(lokey);

	test(k1);

	MyKey k2(LoKey(), 33);
	test(k2);

	MyKey k3((LoKey()));
	test(k3); /* This line produces compilation error */
}


Note that braced initialisation could also be used:

 
MyKey k4 {LoKey ()};


or

 
MyKey k5 {LoKey {}};


or

 
MyKey k6 (LoKey {});


The 'modern' way would be for k5 just using {} without using ().
Last edited on
Thanks a lot. Both replies seem to work fine.
C++11 did add brace initialization syntax to offer a way around the vexing parse:
1
2
MyKey k3(); // function that returns MyKey
MyKey k4{}; // variable 


Hence:
1
2
MyKey k3 { LoKey() }; // or: MyKey k3 { LoKey{} };
test( k3 );



Edit: Note though that a class can have a constructor that takes initializer list.
For example: http://www.cplusplus.com/reference/vector/vector/vector/
1
2
std::vector<int> one {2}; // size() == 1, one[0] == 2
std::vector<int> two (2); // size() == 2 
Last edited on
Topic archived. No new replies allowed.