Domanda

For example I wanted to have a variable of type auto because I'm not sure what type it will be.

When I try to declare it in class/struct declaration it's giving me this error:

Cannot deduce auto type. Initializer required

Is there a way around it?

struct Timer {

    auto start;

};
È stato utile?

Soluzione

You can, but you have to declare it static and const:

struct Timer {
    static const auto start = 0;
};

A working example in Coliru.

With this limitation, you therefore cannot have start as a non-static member, and cannot have different values in different objects.

If you want different types of start for different objects, better have your class as a template

template<typename T>
struct Timer {
    T start;
};

If you want to deduce the type of T, you can make a factory-like function that does the type deduction.

template<typename T>
Timer<typename std::decay<T>::type> MakeTimer(T&& startVal) {   // Forwards the parameter
   return Timer<typename std::decay<T>::type>{std::forward<T>(startVal)};
}

Live example.

Altri suggerimenti

This is what the C++ draft standard has to say about using auto for member variables, in section 7.1.6.4 auto specifier paragraph 4:

The auto type-specifier can also be used in declaring a variable in the condition of a selection statement (6.4) or an iteration statement (6.5), in the type-specifier-seq in the new-type-id or type-id of a new-expression (5.3.4), in a for-range-declaration, and in declaring a static data member with a brace-or-equal-initializer that appears within the member-specification of a class definition (9.4.2).

Since it must be initialized this also means that it must be const. So something like the following will work:

struct Timer
{
  const static int start = 1;
}; 

I don't think that gets you too much though. Using template as Mark suggests or now that I think about it some more maybe you just need a variant type. In that case you should check out Boost.Variant or Boost.Any.

If you declare a class in a lambda expression, you can infer the types of member variables using decltype:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

auto generic_class = [](auto width1, auto height1) {
    class local_class {
        public:
        decltype(width1) width;
        decltype(height1) height;
    } local;
    local.width = width1;
    local.height = height1;
    return local;
};

int main()
{
    auto obj1 = generic_class(3,std::string("Hello!"));
    auto obj2 = generic_class(std::vector<int>{1,2},true);
    cout << obj1.height << "\n";
    cout << obj2.width[0] << "\n";
    return 0;
}

No. Each constructor could have its own initializer for start, so there could be no consistent type to use.

If you do have a usable expression, you can use that:

struct Timer {

   Foo getAFoo();

   delctype(Timer().getAFoo().Bar()) start;

   Timer() : start(getAFoo().Bar()) { /***/ }
};

Indirectly, provided that you don't reference a member of the class.

This can also now be achieved through deduction guides, these were introduced in C++17 and have recently (finally) support in VC++ has been added (clang and GCC already had it).

https://en.cppreference.com/w/cpp/language/class_template_argument_deduction

For example:

template <typename>
struct CString;

template <typename T, unsigned N>
struct CString<std::array<T, N>>
{
    std::array<T, N> const Label;

    CString(std::array<T, N> const & pInput) : Label(pInput) {}
};

template <typename T, std::size_t N>
CString(std::array<T, N> const & pInput) -> CString<std::array<T, N>>;

https://godbolt.org/z/LyL7UW

This can be used to deduce class member types in a similar manner to auto. Although the member variables need to be Dependant somehow on the constructor arguments.

Actually, it would be nice, if a future version of the C++ standard allowed auto also on non-static members, if an initializer is present, as in this simple example:

class C {
    auto a { 0.0 };
    auto b { 3U };
};

This would be equivalent to:

class C {
    decltype(0.0) a { 0.0 };
    decltype(3U) b { 3U };
};

and would save some typing in certain cases, especially, where the initializing expressions are not as simple as here. Of course, the in-class initializers can later be overridden in constructors, but for the typing of the class members, the in-class initializers should take precedence.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top