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.)
Related
Maybe the title is not clear, so concretely:
#include <type_traits>
template<typename T>
constexpr int test(T)
{
return std::is_integral<T>::value;
}
int main()
{
constexpr int a = test(1); // right
constexpr int b = test(1.0); // right
int c = 2;
constexpr int d = test(c); // ERROR!
return 0;
}
In fact, the function doesn't use anything but the type of the parameter, which can be determined obviously in the compilation time. So why is that forbidden and is there any way to make constexpr get the value when only the type of parameter is used?
In fact, I hope to let users call the function through parameters directly rather than code like test<decltype(b)>, which is a feasible but not-convenient-to-use way, to check if the types of parameters obey some rules.
Just take T by reference so it doesn't need to read the value:
template<typename T>
constexpr int test(T&&)
{
return std::is_integral<std::remove_cvref_t<T>>::value;
}
You can even declare test with consteval, if you want to.
(Note that stripping cv-qualifiers isn't necessary in this instance; cv-qualified integral types satisfy the std::is_integral trait.)
Why can't constexpr be used for non-const variables when the function only uses the types?
Because the call expression test(c) is not a constant expression and hence it cannot be used as an initializer for d.
Basically, for the call expression test(c) to be a constant expression, c must be a constant expression. It doesn't matter whether c is used or not inside the function itself. This is why, the call expressions test(1) and test(1.0) works and can be used as an initializer for a and b respectively.
I am using an external library which defines a struct with an unsigned int C-style array:
struct Foo
{
unsigned int bar[8];
}
In my code, I want to get the numeric_limits::max() for that type in order to check out of bounds values, and avoid passing overflowed values to the library.
So I do :
auto n = Foo().bar[0];
if(myBar > std::numeric_limits<decltype (n)>::max())
{
error("The Foo library doesn't support bars that large");
return false;
}
This works, but is there a more elegant c++11 way not implying declaring a variable? If I use decltype(Foo().bar[0]) I have an error, as this returns a reference type, which numeric_limits doesn't like.
For lvalue expressions like Foo().bar[0], decltype yields type T&, i.e. lvalue-reference type.
You can remove the reference part by using std::remove_reference.
std::numeric_limits<std::remove_reference<decltype(Foo().bar[0])>::type>
As an addendum to #songyuanyao's answer, you can avoid having to instantiate Foo by using std::declval, like so:
if (myBar > std::numeric_limits<std::remove_reference<decltype(std::declval <Foo>().bar [0])>::type>::max())
...
Live demo
You could have something like this :
#include <limits>
#include <type_traits>
struct Foo {
unsigned int bar[8];
};
int main() {
auto max_val = std::numeric_limits<std::remove_all_extents_t<decltype(std::declval<Foo>().bar)>>::max();
return 0;
}
std::remove_all_extents removes the "array part" of your member. The advantage is that this will work on simple int, int [], and multi-dimensional arrays too. As you don't make use of the operator[], you avoid the "reference problem" as well.
std::declval allows to determine the type of bar if you don't have an instance at hand.
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
Following my previous question, I found a problem with C++11 too, considering
typedef struct
{
int f_1;
float f_2;
} *Tptr;
this definition of a pointer to an anonymous struct named Tptr, doesn't generates a valid default constructor for the struct that Tptr it's supposed to point to.
This can be verified using the following code
#include <iostream>
typedef struct
{
int f_1;
float f_2;
} *Tptr;
int main()
{
...
Tptr k = NULL;
// trying to initialize a with a copy
decltype(*k) a = decltype (*k)();
// or with an ambiguos call
decltype(*k) a(decltype (*k)());
...
}
Conceptually the decltype(*k) works, thanks to the fact that k is statically declared ( and the resulting type is something like a reference to T, T&, not really a plain T ) .
As I understand what is going on the real problem is that there is no constructor for the pointed struct and I'm wondering why the compiler doesn't create the default special functions for this struct . The compiler has all the information that it needs to build an object that will replicate the required structure in such a way that an instance of Tptr will be able to point to a valid object, so why the compiler doesn't do that ?
The real problem has nothing to do with the lack of a constructor.
decltype(*k) a = decltype (*k)();
This is invalid because decltype (*k) is a reference to your anonymous struct, not your anonymous struct. If you want to get your anonymous struct, you can use std::remove_reference<...>::type:
std::remove_reference<decltype(*k)>::type a = std::remove_reference<decltype(*k)>::type();
decltype(*k) a(decltype (*k)());
This is valid but does not do what you want. This declares a as a function, returning decltype(*k), and taking decltype (*k)() as its parameter. You would need extra parentheses to let it be interpreted the way you want:
decltype(*k) a((decltype (*k)()));
but now you get the same problem as with your first attempt, and you could solve it the same way.
(Of course, in real code, I hope you simply give your struct a name.)
I am trying to use an integer as a template parameter for a class. Here is a sample of the code:
template< int array_qty >
class sample_class {
public:
std::array< std::string, array_qty > sample_array;
}
If I do so something like this, it works:
sample_class< 10 > sample_class_instance;
However, let's say that I do not know the value of array_qty (the template parameter) when compiling, and will only know it during run-time. In this case, I would essentially be passing an int variable as the template argument. For the sake of demonstration, the following code does not work:
int test_var = 2;
int another_test_var = 5;
int test_array_qty = test_var * another_test_var;
sample_class< test_array_qty > sample_class_instance;
I get the following error during compile time when trying the above:
the value of ‘test_array_qty’ is not usable in a constant expression
I've tried converting test_array_qty to a const while passing it as the template parameter, but that doesn't seem to do the trick either. Is there any way to do this, or am I misusing template parameters? Perhaps they need to be known at compile time?
The goal is NOT to solve this specific approach, but rather to find a way to set the length of the array to an int variable that can be stated when instantiating the class. If there is a way to do this via a template parameter, that would be ideal.
Please note that I have to use an array for this, and NOT a vector which I may end up as a suggestion. Additionally, array_qty will always be a value between 0 and 50 - in case that makes a difference.
This can be done in effect. But trust me when I say you are asking the wrong question. So what follows answers your question, even thought doing it is a bad idea almost always.
What you in effect can do is create 50 different programs, one for each of the 50 possible sizes, and then conditionally jump to the one you want.
template<int n>
struct prog {
void run() {
// ...
}
};
template<int n>
struct switcher {
void run(int v) {
if(v==n)
prog<n>::run();
else
switcher<n-1>::run(v);
}
};
template<>
struct switcher<-1> {
void run(int v){
}
};
Call switcher<50>::run( value ); and if value is 0 to 50, prog<value>::run() is invoked. Within prog::run the template parameter is a compile time value.
Horrid hack, and odds are you would be better off using another solution, but it is what you asked for.
Here is a C++14 table-based version:
template<size_t N>
using index_t = std::integral_constant<size_t, N>; // C++14
template<size_t M>
struct magic_switch_t {
template<class F, class...Args>
using R=std::result_of_t<F(index_t<0>, Args...)>;
template<class F, class...Args>
R<F, Args...> operator()(F&& f, size_t i, Args&&...args)const{
if (i >= M)
throw i; // make a better way to return an error
return invoke(std::make_index_sequence<M>{}, std::forward<F>(f), i, std::forward<Args>(args)...);
}
private:
template<size_t...Is, class F, class...Args>
R<F, Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
using pF=decltype(std::addressof(f));
using call_func = R<F, Args...>(*)(pF pf, Args&&...args);
static const call_func table[M]={
[](pF pf, Args&&...args)->R<F, Args...>{
return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
}...
};
return table[i](std::addressof(f), std::forward<Args>(args)...);
}
};
magic_switch_t<N>{}( f, 3, blah1, blah2, etc ) will invoke f(index_t<3>{}, blah1, blah2, etc).
Some C++14 compilers will choke on the variardic pack expansion containing a lambda. It isn't essential, you can do a workaround, but the workaround is ugly.
The C++14 features are all optional: you can implement it all in C++11, but again, ugly.
The f passed basically should be a function object (either a lambda taking auto as the first argument, or a manual one). Passing a function name directly won't work well, because the above best works when the first argument becomes a compile-time value.
You can wrap a function template with a lambda or a function object to help.
For C++ 11, non-type template arguments are restricted to the following (§14.3.2/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
a constant expression that evaluates to a null member pointer value (4.11); or
a pointer to member expressed as described in 5.3.1.
In C++ 98 and 03, the list is even more restricted. Bottom line: what you're trying to do simply isn't allowed.
Template arguments must be compile-time constants aka "constant expressions" or constexprs for short. So there is no way to do is using templates.
You could use a dynamic-sized array and store its size in an int.
Or simply use a vector. Be sure to initialize its size in the constructor by passing the desired size to the vector's constructor!
Sorry, this is not possible. The template argument must be a constant expression known at compile time.
I'm a little late, but here's my suggestion. I'm guessing the main problem with vectors for you is that they allocate a larger capacity than what you need in order to support dynamic growth. So, can't you write your own simple array class?
template <typename T>
class Array {
private:
T* data;
unsigned size;
public:
Array(unsigned size) {
data = new T[size];
this->size = size;
}
T& operator[](int i) {
return data[i];
}
T operator[](int i) const {
return data[i];
}
// Depending on your needs, maybe add copy constructor and assignment operator here.
...
unsigned size() {
return size;
}
~Array() {
delete [] data;
}
}
From what I know, I believe this should be just as fast as the STL array class. In addition, you can create Arrays with sizes unknown until run-time, the Array's memory is handled automatically when it is destroyed, and you don't have to instantiate a new class every time you create a new array with a different size (like you have to do for STL arrays).