increase VS's Intellisense suggestion ability when access template parameter - c++11

I want to access template parameter. This code works :-
template<int s1,int s2> class Setting{public:
static const int setting1=s1;
static const int setting2=s2;
};
class Album{
public: using Setting_unique =Setting<1,2> ;
public: using Setting_share =Setting<4,7> ;
};
template<class Setting_X> class SmartPtr{
public: void doSomething(){
if constexpr(Setting_X::setting1==1){
// ^ intellisense sad :(
}
}
};
int main(){ SmartPtr<Album::Setting_unique> a; }
^ However, the intellisense is not happy with it.
I can't do my ctrl+space.
Below is my trick to make Intellisense works again. It also works :-
class Helper{public: // **new class**
int setting1=0;
int setting2=0;
public: constexpr Helper(int setting1P,int setting2P)
: setting1(setting1P), setting2(setting2P){ }
};
template<int s1,int s2> class Setting{
// **new function**
public: static constexpr Helper getHelper(){return Helper(s1,s2);}
};
class Album{
public: using Setting_unique =Setting<1,2> ;
public: using Setting_share =Setting<4,7> ;
};
template<class Setting_X> class SmartPtr{
static constexpr Helper setting = Setting_X::getHelper();
public: void doSomething(){
if constexpr(setting.setting1==1){
// ^ intellisense happy :) -
// It shows "setting1" & "setting2" in a drop-down list.
}
}
};
int main(){SmartPtr<Album::Setting_unique> a; }
Here is the drop down list I desire :-
The problem is : my code becomes harder to refactor and dirtier.
If I may add a new s3 in the future, there are more locations of codes waiting to be edited.
How to make the intellisense happy, while keep the maintainability-level?
I am using Visual Studio 2017 + Resharper.
(optional) However, it would be cool if the solution doesn't depends on Resharper, or it can be applied to most IDEs as well.
Sorry if this question may sound trivial, but ctrl+space is my life.

Related

Compile time existence checking for a member function with signature fit to variadic parameters pack

I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.
I try to do something like this:
// Note: T object may have several functions with the name foo, but with different signatures.
// a function foo also can be a template one with variadic parameters pack.
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template<typename U>
static bool test(decltype(&U::foo));
template<typename U>
static float test(...);
public:
static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;
//-------------------------------------------------------------^^^^^^^^^
// how to do it?
};
I would like to use it for declaring specific object at compile time - something like this:
class Bar
{
public:
template<typename T, typename...Args>
void doSomthing(T* p, Args&&...parameters)
{
// get correct object type:
// if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;
// compute
ObjType::doSomthing(p, std::forward<Args>(parameters)...);
}
private:
struct A
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
p->foo(std::forward<Args>(parameters)...);
}
};
struct B
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
// do something else
}
};
};
Something like this, perhaps:
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template <typename U>
static std::true_type test(
typename std::enable_if<sizeof(
decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
);
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
Demo

Expand std::vector into parameter pack

I have methods with the following signature:
void DoStuff(int i);
void DoStuff(int i, k);
void DoStuff(int i, int k, int l);
I have a method from where I would like to call the DoStuff methods as follows:
void CallDoStuff(const std::vector<int>& vElements) {
// What magic is supposed to happen here to make vElements an expandable pack?
DoStuff(vElemets...);
}
Is there any chance to achieve this?
Is using std::index_sequence the right way? If yes, could you please provide me a simple example how to apply this to my problem?
The problem is that, from a std::vector, you can't -- compile time -- extract the size() value.
So you can obtain what you want only if you pass, as a compile-time known value, to CallDoStuff() the number of elements that you want to use from the vector.
You can pass it as, by example, a template value.
Using an helper function, you can write something as follows
template <std::size_t ... Is>
void CallDoStuff (std::vector<int> const & vElements,
std::index_sequence<Is...> const &)
{ DoStuff(vElements[Is]...); }
template <std::size_t N>
void CallDoStuff (std::vector<int> const & vElements)
{ CallDoStuff(vElements, std::make_index_sequence<N>{}); }
The call could be something as
CallDoStuff<5u>(v);
If you can use a std::array, instead of std::vector, the answer is different: you can extract the size() from the type itself, so
template <std::size_t N, std::size_t ... Is>
void CallDoStuff (std::array<int, N> const & vElements,
std::index_sequence<Is...> const &)
{ DoStuff(vElements[Is]...); }
template <std::size_t N>
void CallDoStuff (std::array<int, N> const & vElements)
{ CallDoStuff(vElements, std::make_index_sequence<N>{}); }
that is callable without explicating N as follows
std::array<int, 5u> arr { 2, 3, 5, 7, 11 };
CallDoStuff(arr); // no more <5u>
End note: observe that std::make_index_sequence and std::index_sequence are available only starting from C++14. In C++11 you have to substitute them in some way.
It's possible, as long as you provide an upper bound to the number of arguments.
Using Xeo's implementation of std::index_sequence for C++11:
template <unsigned... Idx>
void trampoline(const std::vector<int>& vElements, seq<Idx...>) {
return DoStuff(vElements[Idx]...);
}
template <std::size_t Arity>
void trampoline(const std::vector<int>& vElements) {
return trampoline(vElements, typename gen_seq<Arity>::seq{});
}
template <unsigned... Idx>
void CallDoStuff(const std::vector<int>& vElements, seq<Idx...>) {
using trampoline_t = void (*)(const std::vector<int>&);
constexpr trampoline_t trampolines[]{
trampoline<Idx>...
};
trampolines[vElements.size()](vElements);
}
template <std::size_t Max>
void CallDoStuff(const std::vector<int>& vElements) {
assert(vElements.size() <= Max);
return CallDoStuff(vElements, typename gen_seq<Max + 1>::seq{});
}
See it live on Wandbox
This can't be done, a template method call is bound at compile time but a std::vector doesn't know how many items it contains until runtime so there's no way to mix the two concepts.
DoStuff(vElemets...);
Here the compiler should choose the correct implementation according to how many elements vElements has. You see the flaw in this kind of thinking since std::vector is just an object that could contain any amount of items at point of invocation.

Store parameter pack as tuple references

I am trying to store the parameter pack of lvalue references of a variadic template for later use.
I have the following working for now.
template <typename... Ts>
class Foo {
private:
std::tuple<Ts...> m_args;
public:
template<typename... Args>
Foo(Args&&... args) : m_args(std::make_tuple(std::forward<Args>(args)...))
{
}
};
int main() {
int x = 10;
int y = 20;
Foo<int, int> foo(x, y);
}
However, I would like to store the parameter pack as a reference so that I can access the same object later.
I am not sure how I can do that. Any help would be appreciated.
The best I can imagine, is the use of std::forward_as_tuple.
Unfortunately I don't see a way to use it with perfect forwarding: if you want register values in a tuple inside a class, you have to decide the type of the tuple one time for all.
The best I can imagine is a tuple of const references; something as follows
template <typename ... Ts>
class Foo
{
private:
std::tuple<Ts const & ...> m_args;
public:
Foo (Ts const & ... as) : m_args{std::forward_as_tuple(as...)}
{ }
};
I hope isn't necessary remember you how dangling references can be dangerous for a solution based on a tuple of references.

Getting type_info from variadic template breaks the compiler... why?

So I am essentially trying to shove the rtti of a parameter pack into a list of type_info*. But for some reason, it doesn't seem to compile (or rather the compiler gives up half way through). Either way I can't seem to figure it out. Does anyone have a method to fix this, or better yet, know why it's breaking? Anywho, here's the code:
#pragma once
#include <typeinfo>
#include <vector>
class ParamChecker
{
public:
typedef std::vector<const type_info*> Types;
template <typename T> void PushType()
{
types.push_back(&typeid(T));
}
template <typename Head, typename... Tail> void PushTypes()
{
PushType<Head>();
PushTypes<Tail...>();
}
void PushTypes() {}
private:
Types types;
};
Thanks in advance!
I don't have Visual Studio to test, but I see the problem in your code so I'll tell you about that, and you can test on Visual Studio.
The problem is that, when you recurse into PushTypes<Tail...>(); and Tail... is empty, you're calling, PushTypes<>();. Notice that your base case, void PushTypes() {} is not a template function, i.e. you can't call it via PushTypes<>();.
Also note that you'll need a class template as a helper because we don't have partial specializations for function templates yet (hopefully it'll be coming soon).
But here's what you can do.
#include <typeinfo>
#include <vector>
class ParamChecker {
public:
/* Our type info structure. */
using Types = std::vector<const std::type_info *>;
/* Delegate work to PushTypesImpl<>. */
template <typename... Types>
void PushTypes() {
PushTypesImpl<Types...>()(types_);
}
private:
/* Forward declaration. */
template <typename... Types>
class PushTypesImpl;
/* Collection of type information. */
Types types_;
}; // ParamChecker
/* Base case. */
template <>
class ParamChecker::PushTypesImpl<> {
public:
void operator()(Types &) const { /* Do nothing. */ }
};
/* Recursive case. */
template <typename Head, typename... Tail>
class ParamChecker::PushTypesImpl<Head, Tail...> {
public:
void operator()(Types &types) const {
types.push_back(&typeid(Head));
PushTypesImpl<Tail...>()(types);
}
};
int main() {
ParamChecker x;
x.PushTypes<>(); // push nothing.
x.PushTypes<int>(); // push int.
x.PushTypes<int, double>(); // push int and double.
}
EDIT:
The following is an alternative approach using type_list and passing it as an argument.
NOTE: The use of type_list<> here instead of tuple<> is because constructing an empty tuple requires that all of the types be default-constructable, and even if they were all default-constructable, we don't want to default-construct them for no reason.
template <typename... Types>
class type_list {};
class ParamChecker {
public:
/* Our type info structure. */
using Types = std::vector<const std::type_info *>;
/* Base case. Do nothing. */
void PushTypes(type_list<> &&) {}
/* Recursive case. */
template <typename Head, typename... Tail>
void PushTypes(type_list<Head, Tail...> &&) {
types_.push_back(&typeid(Head));
PushTypes(type_list<Tail...>());
}
private:
/* Collection of type information. */
Types types_;
}; // ParamChecker
int main() {
ParamChecker x;
x.PushTypes(type_list<>()); // push nothing.
x.PushTypes(type_list<int>()); // push int.
x.PushTypes(type_list<int, double>()); // push int and double.
}

Why is Visual Studio using std::iterator<> instead of mine::iterator<>

I've been trying to figure out this problem for a couple days now and finally figured it out after striping everything down to the code below. You'll see in the code below three different attempts at a constructor for const_iterator, along with the errors I get on two of them. It appears to me that the compiler is trying to use std::iterator instead of the locally declared mine::iterator. Is it supposed to be that way?
Other tidbits that have given clues:
If I name mine::iterator something else, like mine::B, then const_iterator(const B &rhs) works.
If I derive const_iterator from a class other than std::iterator, then const_iterator(const iterator<T> &rhs) works.
Thanks for any info. Here's the code:
#include "stdafx.h"
#include <iterator>
namespace mine
{
template <class T>
class iterator : public std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, T*, T&>
{
public:
iterator() {}
};
template <class T>
class const_iterator : public std::iterator<std::random_access_iterator_tag, T, ptrdiff_t, const T*, const T&>
{
public:
const_iterator() {}
const_iterator(const mine::iterator<T> &rhs) {} // works
//const_iterator(const iterator &rhs) {} // error C2440: initializing: cannot convert from 'mine::iterator<T>' to 'mine::const_iterator<T>'
//const_iterator(const iterator<T> &rhs) {} // error C2976: std::iterator: too few template arguments
};
}// namespace mine
using namespace mine;
int _tmain(int argc, _TCHAR* argv[])
{
iterator<int> y;
const_iterator<int> x = y;
return 0;
}
First of all 'using namespace' is evil, use typedef for ease of use. for example instead of saying iterator use mine::iterator.
Also your second point gives the answer of your question. "If I derive const_iterator from a class other than std::iterator, then const_iterator(const iterator<T> &rhs) works."
Here the nearest iterator belongs to std not mine, as std::iterator is the base class of your const_iterator.

Resources