Here is a standalone use case of what I am trying to achieve
//Bar.hpp
#ifndef BAR_HPP
#define BAR_HPP
constexpr bool areNamesEqual(const char* name1,const char* name2)
{
return ((*name1 == *name2) && (*name1 == '\0' || areNamesEqual(name1 + 1,name2 + 1)));
}
#endif
Then I have a class which uses this comparison utility as follows
// Foo.hpp
#ifndef FOO_HPP
#define FOO_HPP
#include "Bar.hpp"
class Foo
{
public:
template<typename T_0>
Foo(const T_0 & var_0)
{
static_assert(areNamesEqual(T_0::formatter_name,"Hole"),"Incorrect hole type supplied!");
}
};
#endif
Finally I have another class, which actually provides an argument for the comparison as follows
// Hole.hpp
#ifndef HOLE_HPP
#define HOLE_HPP
class Hole {
public:
Hole(double dx) : d(dx) {}
static constexpr const char* formatter_name = "Hole";
private:
double d;
};
#endif
In my main.cpp when I invoke this as below
//main.cpp
#include "Foo.hpp"
#include "Hole.hpp"
int main()
{
Foo f(43);
return 0;
}
g++(6.3) with --std=c++14 gives me following error
In file included from main.cpp:1:0:
Foo.hpp: In instantiation of ‘Foo::Foo(const T_0&) [with T_0 = int]’:
main.cpp:6:13: required from here
Foo.hpp:12:36: error: ‘formatter_name’ is not a member of ‘int’
static_assert(areNamesEqual(T_0::formatter_name,"Hole"),"Incorrect hole type supplied!");
Why cant the compiler convert double type to Hole class implicitly ?
I am not sure if conversion operator of Hole class would help me out here.
:UPDATE:
Updated the snippet to show the error for int literal.
Let's analyse the compiler error:
Foo.hpp: In instantiation of ‘Foo::Foo(const T_0&) [with T_0 = int]’:
Means T_0 is deduced to type int (side note: are you sure you are not giving the error when you tried with 43 literal, instead of 43.0?)
So, the type of T_0 is fixed from here. Then:
Foo.hpp:12:36: error: ‘formatter_name’ is not a member of ‘int’.
Which is true: the primitive type int does not have members at all, so it does not have formatter_name member in particular.
This explains the error, which is as-prescribed by the C++ standard.
Now, you mention expecting conversion, is it because of the non-explicit constructor for Hole taking a double?
If so, this conversion would implicitly happen only if you gave a double to a "context" expecting an Hole instance.
E.g, if you changed the Foo initialization to Foo f<Hole>(43.0); or Foo f(Hole{43.0});
This is absolutely not the case in you example: you give a double to Foo constructor that is templated on the argument type, and you do not force the template type yourself. So function template type deduction kicks-in, and it exactly matches the argument type. Additionally, implementing any conversion operator would not change that fact.
Related
I am trying to execute following code using g++ and getting incomplete type error
#include <stdio.h>
struct try_main{
union{
struct try_inner_one{
int fl;
float g;
}one;
struct try_inner_two{
char a;
}two;
}un;
int chk;
};
void func(struct try_inner_one o){
printf("%d\n",o.fl);
}
int main(){
struct try_main z = {{1,2},3};
func(z.un.one);
return 0;
}
Error:
union.c: In function ‘void func(try_inner_one)’:
union.c:15:6: error: ‘o’ has incomplete type
void func(struct try_inner_one o){
^
union.c:15:18: error: forward declaration of ‘struct try_inner_one’
void func(struct try_inner_one o){
^
union.c: In function ‘int main()’:
union.c:20:16: error: parameter 1 of ‘void func(try_inner_one)’ has incomplete type ‘try_inner_one’
func(z.un.one);
Above code is successfully getting compiled with gcc
What is the reason for this error and how to fix this
Thanks
C and C++ have different scoping rules. The full name of the type in C++ isn’t struct try_inner_one, since the type definition is nested inside the unnamed union inside try_main.1
If you want to write code that works equally in both C and C++, pull the type definition to the top level:
struct try_inner_one {
int fl;
float g;
};
struct try_inner_two {
char a;
};
struct try_main {
union {
struct try_inner_one one;
struct try_inner_two two;
} un;
int chk;
};
1 The fully qualified name of this type can’t be spelled in C++ since the type it’s nested inside is unnamed. You could give a name to the union type, that would allow you to spell the fully qualified name of try_inner_one in C++. However, that name wouldn’t be legal C code, since C doesn’t have a scope resolution operator.
If you want to keep the nested type definition you could give the union a name (in the following, union_name) and do the following to keep the code compiling for both C and C++:
// (Type definition omitted.)
#ifdef __cplusplus
using try_inner_one = try_main::union_name::try_inner_one;
#else
typedef struct try_inner_one try_inner_one;
#endif
void func(try_inner_one o){
printf("%d\n", o.fl);
}
What is the reason for this error
The reason is that try_inner_one nested within the union nested within try_main cannot be found by unqualified name lookup in the context outside of that union in C++ (unlike in C).
how to fix this
You can use a qualified name in C++:
void func(decltype(try_main::un)::try_inner_one o){
You can simplify if you give a name for the union:
union u { // note the name
struct try_inner_one{
void func(try_main::u::try_inner_one o){
A cross-language compatible solution is to define the struct outside of each other as described in Kondrad Rudolph's answer.
A word of warning: C++ is more restrictive than C on how inactive members of union can be accessed.
It seems you are compiling your program as a C++ program. In this case each declaration within the structure try_main has the scope of this structure.
So you need to declare the function like
void func( decltype( try_main::un )::try_inner_one o );
or
void func( const decltype( try_main::un )::try_inner_one &o );
Using c++17 and gmock, I am mocking a class and would like to redirect calls to one of its member functions to a lambda. Is this possible?
He're a minimal example:
#include <gmock/gmock.h>
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
class Foo
{
public:
virtual uint8_t MyCall(const uint8_t in) const
{
return in;
}
};
class MockFoo : public Foo
{
public:
MOCK_METHOD(uint8_t, MyCall, (const uint8_t), (const, override));
};
TEST(MyTest, MyTestCase)
{
MockFoo mock_foo;
ON_CALL(mock_foo, MyCall(_)).WillByDefault(Invoke([](const uint8_t to) {
static_cast<void>(to);
}));
}
I am getting the following error when compiling:
demo.cpp: In member function 'virtual void MyTest_MyTestCase_Test::TestBody()':
demo.cpp:82:7: error: no matching function for call to 'testing::internal::OnCallSpec<unsigned char(unsigned char)>::WillByDefault(std::decay<MyTest_MyTestCase_Test::TestBody()::<lambda(uint8_t)> >::type)'
}));
^
In file included from external/gtest/googlemock/include/gmock/gmock-function-mocker.h:42:0,
from external/gtest/googlemock/include/gmock/gmock.h:61,
from demo.cpp:2:
external/gtest/googlemock/include/gmock/gmock-spec-builders.h:323:15: note: candidate: testing::internal::OnCallSpec<F>& testing::internal::OnCallSpec<F>::WillByDefault(const testing::Action<F>&) [with F = unsigned char(unsigned char)]
OnCallSpec& WillByDefault(const Action<F>& action) {
^~~~~~~~~~~~~
external/gtest/googlemock/include/gmock/gmock-spec-builders.h:323:15: note: no known conversion for argument 1 from 'std::decay<MyTest_MyTestCase_Test::TestBody()::<lambda(uint8_t)> >::type {aka MyTest_MyTestCase_Test::TestBody()::<lambda(uint8_t)>}' to 'const testing::Action<unsigned char(unsigned char)>&
The return type of your lambda does not match that of your member function
The error messages of gmock can be somewhat cryptic, and it doesn't help when you are working with types that are typedefs to fundamental types; in this case uint8_t.
If we look closer at the error message:
error: no matching function for call to
'testing::internal::OnCallSpec<unsigned char(unsigned char)>
::WillByDefault(std::decay<MyTest_MyTestCase_Test::TestBody()
::<lambda(uint8_t)> >::type)'
it's actually providing some hints:
the OnCallSpec of unsigned char(unsigned char),
does not match the type of the provided (WillByDefault) callable.
The former, when looking at your program and manually translating in the fixed-width typedefs, actually tell us:
the OnCallSpec of uint8_t(uint8_t),
which makes it more apparent that something is wrong with the type of the default callable, namely the lambda.
In this particular case, the return type of the lambda is (implicitly) void, thus the mismatch of (disregarding CV-qualifiers) void(uint8_t) with the "on call spec" of uint8_t(uint8_t).
I'm having difficulty figuring out why the following bit of code, with the dependencies shown, does not compile and would appreciate help help fixing it.
main.cpp
#include <cstdlib>
#include <iostream>
#include "Foo.h"
#include "Bar.h"
int main()
{
Foo<Bar> f1; // ERROR
Foo<Bar,true> f2; // works
return EXIT_SUCCESS;
}
Foo.h
template<typename T, bool S = T::HAS_NATIVE_SUPPORT>
struct Foo
{
};
Bar.h
struct Bar
{
static const bool HAS_NATIVE_SUPPORT;
};
Bar.cpp
#include "Bar.h"
const bool Bar::HAS_NATIVE_SUPPORT = true;
I get the following error in the Visual Studio 2008 Command Prompt
cl main.cpp Bar.cpp
main.cpp(12) : error C2975: 'S' : invalid template argument for 'Foo', expected compile-time constant expression
c:\tmp\c++tests\so\Foo.h(1) : see declaration of 'S'
In the g++ (GCC) 4.5.3 I get the following error message:
$ g++ main.cpp Bar.cpp
main.cpp: In function ‘int main()’:
main.cpp:12:9: error: ‘Bar::HAS_NATIVE_SUPPORT’ is not a valid template argument for type ‘bool’ because it is a non-constant expression
main.cpp:12:12: error: invalid type in declaration before ‘;’ token
The values of template parameters have to be known at compile time, but by initializing the value of the member in another source file, the compiler can't see what the value is when it needs it.
You need to initialize your static member in the class for it to be usable as compile-time constant:
struct Bar
{
static const bool HAS_NATIVE_SUPPORT = true;
};
A static member variable is only compile time constant if it is also initialized inside the class body.
So either initialize it there, or use one of the following variants:
template <bool B>
void Y () {}
struct X {
enum { foo = true };
enum : bool { bar = true };
static const bool frob = true;
static constexpr bool frobnicate = true;
};
int main () {
Y<X::foo>();
Y<X::bar>();
Y<X::frob>();
Y<X::frobnicate>();
}
The code below works as long as I keep it all in the "main.cpp" file.
//#include "Travel.h"
//#include "Obj.h"
// "Travel.h"
typedef int travel_t;
class Travel
{
public:
static const travel_t AIR;
static const travel_t WATER;
static const travel_t LAND;
};
// "Travel.cpp"
// #ifndef TRAVEL_H
// #define TRAVEL_H
//
// #include "Travel.h"
const travel_t Travel::AIR = -2;
const travel_t Travel::WATER = -1;
const travel_t Travel::LAND = 0;
// #endif //TRAVEL_H
// "Obj.h"
// #ifndef OBJ_H
// #define OBJ_H
//
//#include "Travel.h"
template<typename T, travel_t travel>
class Obj
{
public:
void foo(){};
};
// #endif //OBJ_H
// "main.cpp"
int main()
{
Obj<int, Travel::AIR> objAirTravel;
objAirTravel.foo();
return 0;
}
However, as soon as I moved code to different headers and implementation files as indicated, it doesn't compile any more. :-( How can I fix that problem? What is the problem/rule behind it? This is the compiler error I get (using gcc):
main.cpp|45|error: 'Travel::AIR' is not a valid template argument for type 'int' because it is a non-constant expression|
main.cpp|45|error: invalid type in declaration before ';' token|
main.cpp|47|error: request for member 'foo' in 'objAirTravel', which is of non-class type 'int'|
In order to use a constant as a template argument, its value must be available in the current translation unit. When you move the definition of Travel::Air to a different source file, its value is no longer available to the compiler in main.
Since it's an integer constant, you can declare the value in the declaration inside the class:
class Travel
{
public:
static const travel_t AIR = -2;
static const travel_t WATER = -1;
static const travel_t LAND = 0;
};
Now the values are available to use as template arguments in any translation unit that includes this class definition.
I want to use a boost::ptr_map inside a specific class which stores instances of itself. However, please consider the following example:
#include <boost/checked_delete.hpp>
#include <boost/ptr_container/ptr_map.hpp>
class foo
{
friend void boost::checked_delete<>(foo*);
~foo() {}
};
int main()
{
boost::checked_delete(new foo); // OK
boost::ptr_map<int, foo> foo_map; // error C2248: 'foo::~foo' : cannot access private member declared in class 'foo'
return 0;
}
The error happens at the following line
// verify that types are complete for increased safety
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x; // error C2248
}
What exactly is going on here? Shouldn't it work? I assume that the problem is that templates are defined in the compilation unit they are included in and boost::checked_delete is called from another compilation unit in the implementation source of bosst::ptr_map. So, it's not the same function I declared as a friend.
However, is there a workaround for this problem?
Try this syntax when declaring the friend:
template <class T>
friend void boost::checked_delete(T*);
Here is the start of the huge error message* from GCC, which is the start of the chain of instantiations (usually, and in this case):
In file included from main.cpp:1:0:
main.cpp: In function 'void boost::checked_delete(T*) [with T = const foo]':
Adding
friend void boost::checked_delete<>(foo const*);
makes the code compile.
(*): 13 lines and 3510 characters for 270 chars/line