Question

Given the class template

template<class T>
struct A {
    A( const T & x );
};

I would like to instantiate objects of this class without writing out the actual type T, because this is typically a clumsy type resulting from some sort of expression templates and lambda functions. One way to accomplish this would be

template<class T>
A<T> create_A( const T& t ){ 
    return A<T>( t );
}

int main(){
    auto a = create_A( complicated_expression );
}

Here I never wrote the actual type of the expression, but this creates a copy of A and won't work without a copy constructor. I don't have a copy (or move) constructor. What I'm looking for is something like

A a( complicated_expression );

Clean and simple, and the compiler should be able to figure out the actual type. Unfortunately this isn't valid C++. So what would be the best valid C++ syntax to accomplish the same thing? Currently I'm doing this:

auto x = complicated_expression;
A<decltype(x)> a(x);

But this seems unnecessary verbose. Is there a better way to do this?

Was it helpful?

Solution 2

Well, if your compiler is MSVC, this will work:

template<class T>
struct A {
    A(const T & x) {}

    A(const A&) = delete;
    A(A&&) = delete;
};


template <typename T>
A<T> create_A(const T& t)
{
    return t;
}

const auto& a = create_A(666);
const auto& b = create_A(a);
const auto& c = create_A(b);

No such luck with clang and g++, though.

Assigning a result returned by value to a const reference is perfectly legal, by the way, and has its uses. Why MSCV avoids checking for type being moveable/copyable (even though it would optimise it away) is a mystery to me and likely a bug. But, it'd kinda work in your case if you need to do it this way.

EDIT: alternatively, if you are not afraid to bring the wrath of C++ gods upon yourself, you can transform create_A into a macro:

#define create_A(x) (A<decltype(x)>(x))

Now it shall work on all compilers.

EDIT2: as @dyp suggested, this answer can be improved further:

template <typename T>
A<T> create_A(const T& t)
{
    return { t };
}

auto&& a = create_A(666);
auto&& b = create_A(a);
auto&& c = create_A(b);

It will work on all C++11 compilers.

OTHER TIPS

The code

template<class T>
A<T> create_A( const T& t ){ 
    return A<T>( t );
}

int main(){
    auto a = create_A( complicated_expression );
}

formally requires copy or move constructor to be defined and available, but any reasonable compiler will be able to optimize it away using copy elision rule. It is the standard idiom used widely across the standard library (e.g. std::make_pair).

The technique you're trying to implement is called template argument deduction.

So, I don't think you can achive something like:

A a( complicated_expression );

Since here A is the template's name and the template argument deduction takes place only in functions. Not in classes. With the line above you will not be able to avoid the missing template arguments error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top