Disable implicit conversion between typedefs - c++

In C++11, is there a clean way to disable implicit conversion between typedefs, or do you have to do something nasty like wrap your int in a class and define and delete various operators?
typedef int Foo;
typedef int Bar;
Foo foo(1);
Bar bar(2);
bar = foo; // Implicit conversion!

HelloWorld explains why what you have cannot work. You'll need what's typically called a "strong" typedef to do what you want. An example implementation is BOOST_STRONG_TYPEDEF:
#include <boost/serialization/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(int, a)
void f(int x); // (1) function to handle simple integers
void f(a x); // (2) special function to handle integers of type a
int main(){
int x = 1;
a y;
y = x; // other operations permitted as a is converted as necessary
f(x); // chooses (1)
f(y); // chooses (2)
}
If we had done typedef int a;, then the code would be ambiguous.

The C++ standard says:
7.1.3 The typedef specifier
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does
not introduce a new type the way a class declaration (9.1) or enum declaration does
But e.g. class or struct introduce new types. In the following example uniqueUnused does actually nothing but is used to create a different type Value<int, 1> != Value<int, 2>. So maybe this is something you are looking for. Keep in mind there is no guarantee the compiler gets rid of the outer structure! The only guarantee this code gives you it's the same size as int
template<typename T, int uniqueUnused>
struct Value
{
Value() : _val({}) {}
Value(T val) : _val(val) { }
T _val;
operator T&() { return _val; }
// evaluate if you with or without refs for assignments
operator T() { return _val; }
};
using Foo = Value<int, 1>;
using Bar = Value<int, 2>;
static_assert(sizeof(Foo) == sizeof(int), "int must be of same size");
static_assert(sizeof(Bar) == sizeof(int), "int must be of same size");
If you want to create a new type based on a class you can simply go with this example (this doesn't work with scalar types since you can't inherit from ints):
class Foo : public Bar // introduces a new type called Foo
{
using Bar::Bar;
};

I wanted to do something similar to keep different indexes separated not only logically, but also enforced by the compiler. The solution I came up with is basically to just define structs with one element. In some ways it's more painful to use, but it works very well with my situation since I often don't need to deal with the actual value of the index for a lot of my code, just passing it around.
typedef struct{uint16_t i;} ExpressionIndex;
typedef struct{uint16_t i;} StatementIndex;
Now, trying to do
ExpressionIndex foo() {
StatementIndex i;
return i;
}
yields the error error: incompatible types when returning type ‘StatementIndex’ but ‘ExpressionIndex’ was expected
Converting between types is a bit painful, but that was the intent of my change.
ExpressionIndex exp = (ExpressionIndex){stmt.i};

It's not strict type-checking, but illegal conversions can made visible by using original, or Apps Hungarian Notation (H. N.). If you think H. N. means name-type-as-prefix, you're wrong (it's System H. N., and it's, hm, unnecessary naming overhead).
Using the (Apps) H. N., the variable prefix marks not the type (e.g. int), but the purpose, e.g. counter, length, seconds etc. So, when you add a counter to a variable contains elapsed time, you write cntSomethingCounter + secElapsedSinceLastSomething, and you can see that it smells. Compiler does not alerts, but it pokes your eyes.
Read more: http://www.joelonsoftware.com/articles/Wrong.html

Related

Result of decltype in const methods

The C++11 decltype returns the type of the expression given to it (mostly). But this can differ from the type of the expression as it is actually accessible:
template<typename T>
struct Ref {
Ref(T&) { }
};
#define GETTYPE decltype
//#define GETTYPE typeof
struct Problem {
void doit_c() const { Ref<GETTYPE(n)> rn{n}; }
void doit_nc() { Ref<GETTYPE(n)> rn{n}; }
int n;
};
int main() {
int i;
const int ci = 0;
Problem pr;
// decltype == typeof == int
Ref<GETTYPE(i)> ri{i};
pr.doit_nc();
// decltype == typeof == const int
Ref<GETTYPE(ci)> rci{ci};
Ref<GETTYPE(static_cast<const int&>(i))> rcci{static_cast<const int&>(i)};
// typeof == const int, decltype == int (!)
pr.doit_c();
return 0;
}
In the example, the Ref struct is just used to cause a compile error if T does not match the actual constructor argument. The Problem::doit_c() method is where decltype(n) returns a non-const result, even though n is const in this context.
If one switches from the standard decltype to the GNU extension typeof, this seems to take the const-ness of the method into account.
Now my question: Is there a C++11 / C++14 / C++17 compliant alternative to decltype() / typeof() that behaves "correctly" (as in: no compile error above) for expressions like the declaration in the const-method above?
Edited:
Simplified the first sentence to remove some errors and stop distracting from the point of the question (thanks, #skypjack)
Simplified the use use of macros in the example code (thanks, #Richard Critten)
decltype is a feature that kinda sits at two chairs at once. Firstly, as the name suggests, it can give you the exact declared type of an entity, ignoring the context in which it is used. Secondly, it can treat its argument as an expression, whose exact type depends on the context and its value category.
decltype applied directly to a "naked" (unparenthesized) class member access is a special case, in which decltype acts in accordance with its first role. It will not treat n as an expression. Instead it will produce the type of that class member, ignoring the context.
If you want it to treat n as an expression, you have to parenthesize it
struct Problem {
void doit_c() const
{
Ref<decltype(n)> rn1{n}; // `decltype(n)` is `int` -> ERROR
Ref<decltype((n))> rn2{n}; // `decltype((n))` is `const int &` -> compiles OK
}
};
You can find out the effective cv-qualified type of n using a temporary reference:
void doit_c() const { auto& x = n; Ref<GETTYPE(x)> rn{n}; }
void doit_nc() { auto& x = n; Ref<GETTYPE(x)> rn{n}; }
But it's simpler and clearer to parenthesize, as shown in AnT's answer.

using an absolute pointer address as a template argument

I have a template class which takes as its first template argument a foo * pointer. I'd like to instantiate one of these with a foo located at an absolute address, like so:
class foo
{
int baz;
};
template<foo *f> class bar
{
public:
bar() {}
void update() { /* ... */ }
};
// ....
#define FOO_ADDR ((foo *)0x80103400)
#define FOO_NULL ((foo *)0)
foo testFoo;
bar<FOO_ADDR> myFoo; // fails with non-integral argument
bar<FOO_NULL> huh; // compiles, I was surprised by this
bar<&testFoo> test; // compiles as expected (but not useful)
Does anyone know if it's possible without resorting to the linker and getting FOO_ADDR to be defined with external linkage?
This is with the Keil ARM C/C++ Compiler version V5.06 update 1 (build 61), I've tried switching on C++11 mode but (apart from throwing a load of new errors in the system headers) it didn't change the behaviour.
Update: here's the proposed solution (with the real code this time) using int casts
template<uint32 PORT, uint32 BIT, uint32 RATE> class LedToggle
{
uint32 mTicks;
uint32 mSetReset;
public:
LedToggle()
{
mTicks = 0;
mSetReset = 1 << BIT;
}
void Update()
{
uint32 mask = ((mTicks++ & RATE) - 1) >> 31;
((GPIO_TypeDef *)PORT)->BSRR = mSetReset & mask;
mSetReset ^= ((1 << BIT) | (1 << (BIT + 16))) & mask;
}
};
LedToggle<(uint32)GPIOC, 13, 1023> led;
It's pretty ugly, but it does work. I'd be interested to hear if anyone can improve on it?
The declaration bar<(foo*)0x80103400> myFoo; is ill-formed because non-type template arguments must be a constant expression, from [temp.arg.nontype]:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter.
And the argument you are passing is not, from [expr.const]:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the
abstract machine (1.9), would evaluate one of the following expressions:
— [...]
— a reinterpret_cast (5.2.10);
— [...]
The declaration bar<(foo*)0> huh works since it does not involve a cast, it's simply a null pointer of type foo* (0 is special) and so it is a valid constant expression.
You could instead simply pass in the address as a template non-type parameter:
template <uintptr_t address>
struct bar { ... };
bar<0x8013400> myFooWorks;
That is viable.
Facing the same problem (on an STM32), as a work-around I found function pointer template parameters, like so:
template<GPIO_TypeDef* PORT(), uint32 BIT, uint32 RATE>
class LedToggle
{
public:
void Update()
{
// ...
PORT()->BSRR = mSetReset & mask;
// ...
}
};
constexpr GPIO_TypeDef* Port_C() {
return PORTC;
}
LedToggle<Port_C, 13, 1023> led;
Notice that we use a function pointer as template parameter, to a function that returns the desired actual pointer. Inside that function casts are allowed; and since the function is declared constexpr the compiler may (should) optimize away the actual function call and use the function's return value like a literal.
Casting to/from ints works, but as pointed out, it's dangerous. Another solution similar to JimmyB's is to use enum classes instead of function pointers. The enum class member values are set to the device addresses as specified inthe vendor-supplied header. For instance, for the STM32 series, ST provides a header with the following defined:
// Vendor-supplied device header file (example)
#define GPIOA_BASE = 0x40001000
#define GPIOB_BASE = 0x40002000
// etc...
In your code, create an enum class:
#include <vendor-supplied-device-header.h>
enum class GPIO : uint32_t {
A = GPIOA_BASE,
B = GPIOB_BASE,
C = GPIOC_BASE,
D = GPIOD_BASE,
E = GPIOE_BASE,
F = GPIOF_BASE,
G = GPIOG_BASE,
#ifdef GPIOH_BASE //optional: wrap each member in an #ifdef to improve portability
H = GPIOH_BASE,
#endif
//.. etc
};
To avoid multiple messy casts, just do it once in the class using a private method. For example then your LedToggle class would be written like this:
template<GPIOPORT PORT, uint8_t PIN, uint32_t RATE> class LedToggle
{
static_assert(PIN < 15, "Only pin numbers 0 - 15 are valid");
volatile auto GPIOPort(GPIOPORT PORT) {
return reinterpret_cast<GPIO_TypeDef *>(port_);
}
uint32_t mTicks;
uint32_t mSetReset;
public:
LedToggle()
{
mTicks = 0;
mSetReset = 1 << PIN;
}
void Update()
{
uint32 mask = ((mTicks++ & RATE) - 1) >> 31;
GPIOPort(PORT)->BSRR = mSetReset & mask;
mSetReset ^= ((1 << PIN) | (1 << (PIN + 16))) & mask;
}
};
LedToggle<GPIO::C, 13, 1023> led;
The benefit of this method is that the class users are forced to use only members of the GPIO enum class, therefore invalid addresses are prohibited.
You can use enum classes for any of the template parameters, for instance you could replace the PIN parameter with an enum class whose members are set to the vendor's specified GPIO_PIN_1, GPIO_PIN_2, etc. Then you'd write:
LedToggle<GPIO::C, Pin::_13, 1023>
From the C++11 Standard (emphasis mine):
14.3.2 Template non-type arguments
1 A template-argument for a non-type, non-template template-parameter shall be one of:
— for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or
— the name of a non-type template-parameter; or
— a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or
— a constant expression that evaluates to a null pointer value (4.10); or
When compiled with g++ -Wall, I get the following error:
error: ‘2148545536u’ is not a valid template argument for ‘foo*’ because it is not the address of a variable
bar<FOO_ADDR> myFoo; // fails with non-integral argument
^
It seems that the compiler is able to detect that 0x80103400 is not the address of a variable, it's just a constant expression.
Have you try casting the pointer address to and from uintptr_t, which is an unsigned integer capable of holding a pointer value?
The type is defined in a standard header <cstdint> but it is only optional. If it does not exist in your version of C++, try size_t instead.
A full example would then look like:
#include <cstdint>
class foo
{
int baz;
};
template<uintptr_t addr> class bar
{
constexpr static const foo* f = (foo*)(addr);
public:
bar() {}
void update() { }
};
#define FOO_ADDR ((uintptr_t)0x80103400)
int main() {
bar<FOO_ADDR> myFoo;
}
The obvious drawback is that there is no typechecking at the template parameter. You pass a value which will hopefully refer to foo object and not a different one.
Not to mention that we are in the undefined behavior world as far as the standard goes....
You seem to be able to compile with the line
constexpr static const foo* f = reinterpret_cast<foo*>(addr);
with at least some of the compilers as well (http://coliru.stacked-crooked.com/a/5af62bedecf2d75a)
If your compiler rejects casting in the context of constexpr as it is ill-formed (as per Barry's comment) you can define it as a regular static const variable:
template<uintptr_t addr>
class bar
{
static const foo* f;
public:
bar() {}
void update() { }
};
template<uintptr_t addr>
const foo* bar<addr>::f = reinterpret_cast<foo*>(addr);
Less ideal but solves that problem hopefully.
First, don't use c-style casts. It doesn't make it explicit what is does.
Second, you will realize that in order to cast an arbitrary number into a pointer, you need to use reinterpret_cast. This sort of cast is not allowed in constexpr expressions.
Since template parameters are only possible with constant expressions, an arbitrary number as a pointer is not possible.
The case where 0 is possible is because 0 is convertible to nullptr, which is constant expression.

What is the merit of the "function" type (not "pointer to function")

Reading the C++ Standard, i see that there are "function" types and "pointer to function" types:
typedef int func(int); // function
typedef int (*pfunc)(int); // pointer to function
typedef func* pfunc; // same as above
I have never seen the function types used outside of examples (or maybe i didn't recognize their usage?). Some examples:
func increase, decrease; // declares two functions
int increase(int), decrease(int); // same as above
int increase(int x) {return x + 1;} // cannot use the typedef when defining functions
int decrease(int x) {return x - 1;} // cannot use the typedef when defining functions
struct mystruct
{
func add, subtract, multiply; // declares three member functions
int member;
};
int mystruct::add(int x) {return x + member;} // cannot use the typedef
int mystruct::subtract(int x) {return x - member;}
int main()
{
func k; // the syntax is correct but the variable k is useless!
mystruct myobject;
myobject.member = 4;
cout << increase(5) << ' ' << decrease(5) << '\n'; // outputs 6 and 4
cout << myobject.add(5) << ' ' << myobject.subtract(5) << '\n'; // 9 and 1
}
Seeing that the function types support syntax that doesn't appear in C (declaring member functions), i guess they are not just a part of C baggage that C++ has to support for backward compatibility.
So is there any use for function types, other than demonstrating some funky syntax?
On the one hand, you seem to be talking about function types in general. On the other hand, it appears that your question is really about the usability of typedef names for function types.
The function types themselves is a fundamental concept built into both C and C++ languages. They are used all the time. You just can't live without them. Every time you declare a function you declare an entity of function type. Every time you use a pointer to a function, you use a pointer to function type. Etc.
As for the possibility of making typedef names for function types... I don't see much use for it. It is, I think, a part of C baggage, that was extended a bit for C++ just because it was easy to do.
As you correctly noted typedef names for function types can be used to declare member functions (and in C++ you can also include const specifier into typedef, as in typedef int MemberType() const;), but, for example, you can't use this feature with function types passed as template parameters.
An example of why this is useful is boost, where you see this a lot. For example in the signals2 library:
boost::signals2::signal<void (int, int)> MySignal;
where the above declares a signal that will accept any function that takes two ints and has a void return type.
boost:function uses that syntax, called "preferred" syntax.
Seems that kind of syntax is not widely used? Comparing to function pointer.
You see it in the new function objects in Boost/TR1/C++0x.
std::function<void()> accepts any object with an operator() that returns void and takes no arguments.

friend declaration in C++

In Thinking in C++ by Bruce eckel, there is an example given regarding friend functions as
// Declaration (incomplete type specification):
struct X;
struct Y {
void f(X*);
};
struct X { // Definition
private:
int i;
public:
friend void Y::f(X*); // Struct member friend
};
void Y::f(X* x) {
x->i = 47;
}
Now he explained this:
Notice that Y::f(X*) takes the address of an X
object. This is critical because the compiler always knows how to
pass an address, which is of a fixed size regardless of the object
being passed, even if it doesn’t have full information about the size
of the type. If you try to pass the whole object, however, the
compiler must see the entire structure definition of X, to know the
size and how to pass it, before it allows you to declare a function
such as Y::g(X).
But when I tried
void f(X);
as declaration in struct Y, it shows no error.
Please explain why?
The parameter types for function declarations may be incomplete.
For data member declarations and all definitions however, the type has to be complete:
struct A;
struct B {
void f(A); // declaration, fine
void g(A) {} // error
A a; // error
};
It should be fine to pass the incomplete object X by value, though during the function implementation the complete type X must be available irrespective of whether the object of type X is actually used in function or not.
A function declaration is all fine with incomplete object as argument or return type, except covariant return type (for member function) where such return type must be complete type.
The problems is when you change the declaration in struct X.
So, inside struct X you tell the compiler the struct has a function which receives something of type X, but wait a minute, type X is not fully define at this point!
You can't use an incomplete type as a parameter for function f but you can use the address of an incomplete type, thus X*.
On a site note, it will be very important for you to increase your acceptance rate so you get answers for your future questions and important for my ego if i got the right answer :)

Is there pointer to member traits or something like this?

Based on other my question.
Consider the following code
template<typename T, int N>
struct A {
typedef T value_type; // save T to value_type
static const int size = N; // save N to size
};
Look, I can use value_type and size as template parameter.
typedef A<int, 2> A1;
typedef A<A1::value_type, A1::size + 3> A2; // OK, A2 is A<int,5>
Now I want to do the same with pointer to member:
struct Foo {
int m;
int r;
};
template<int Foo::*Mem>
struct B {
static int Foo::* const mp;
};
template<int Foo::*Mem>
int Foo::* const B<Mem>::mp = Mem; // Save pointer to member
But I get error.
typedef B<&Foo::m> B1;
typedef B<B1::mp> B2; // DOES NOT WORK
How to make last line to work?
Or how to get similiary result?
Note. I know that it does not work. No links to C++ Standard is needed.
I need workaround.
It shouldn't work according to C++ Standard 5.19/2:
Other expressions are considered constant-expressions only for the purpose of non-local static object initialization (3.6.2). Such constant expressions shall evaluate to one of the following:
— a null pointer value (4.10),
— a null member pointer value (4.11),
— an arithmetic constant expression,
— an address constant expression,
— a reference constant expression,
— an address constant expression for a complete object type, plus or minus an integral constant expression,
or
— a pointer to member constant expression.
It is not the answer to the original question, but it is the answer to this wrong statement.
Mike is right that it should compile. This is a bug in VS.
Not totally an answer but do accessing Mem directly work?
ie: B1::Mem instead of B1::mp.
I'm pretty sure the standard do not allow it since we normally typedef template name when it's a type instead of accessing it directly, but technically it could maybe allow it (not sure what would be the implication). Where your solution is probably sure not to work since it require initialisation of a static member that is done at runtime (correct me if I'm wrong), so it cannot be accessed at compile time like you want to do.
Maybe you could try giving us the bigger picture of what you're trying to do with your trait/policy class to see if a suitable workaround is possible.
I was surprised to find that there is not such thing. At least in the expected places, for example:
There is nothing here http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/index.html
nor near here http://en.cppreference.com/w/cpp/types/is_member_pointer
Based on this http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html and this http://en.cppreference.com/w/cpp/types/is_member_pointer it is not hard to roll your own.
#include<type_traits> // std::is_pointer_member
template<class MP> struct member_pointer_traits_helper;
template< class T, class U >
struct member_pointer_traits_helper<T U::*>{
using class_type = U;
using declaration_type = T;
};
template< class MP >
struct member_pointer_traits :
member_pointer_traits_helper<typename std::remove_cv<MP>::type> {};
struct B{
int b;
};
int main(){
using std::same;
static_assert(std::is_member_pointer<int B::*>::value == true, "");
static_assert(is_same<member_pointer_traits<int B::*>::class_type, B>{}, "");
static_assert(is_same<member_pointer_traits<int B::*>::declaration_type, int>{}, "");
static_assert(is_same<member_pointer_traits<decltype(&B::b)>::declaration_type, int>{}, "");
// static_assert(is_same<member_pointer_traits<double>::class_type, B>{}, ""); // error
}
I am not sure if the names are optimal.
Also when applied to non member pointer this will give a compiler error (this design is copied from http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html), another alternative could be to return the void type (which is obviously a failure return because void cannot be a class or a member type.)
(with some small modifications it can be used with C++98, used C++11 to make it more clear.)