xerion
xerion

Reputation: 303

Auto deduction for templates

I had a question yesterday in stackoverflow on achieving specific conversions between different template types.

This is the class that was almost proposed. I say almost because I changed small parts of it in hope of simplifying it.

#include <iostream>
#include <type_traits>
// Helper class

template<bool from, bool to> 
struct ok_to_copy_foos : std::false_type {};

// Define all valid conversions as specializations:

template<>
struct ok_to_copy_foos<false, false> : std::true_type {};

template<>
struct ok_to_copy_foos<true, false> : std::true_type {};

////////////////////////////////////////////////////////////////////

template<bool Owner>
class Foo {

static constexpr bool owner_ = Owner;

public:

    Foo() {}

    Foo(const Foo &o)
    {
        static_assert(ok_to_copy_foos<Owner, Owner>::value, "can only copy from Foo<true> to Foo<false>");
    }

    Foo& operator=(const Foo& foo) 
    {
        static_assert(ok_to_copy_foos<Owner, Owner>::value, "can only assign from Foo<true> to Foo<false>");
        return *this;
    }

    template<bool U>
    Foo(const Foo<U> &)
    {
        static_assert(ok_to_copy_foos<Owner, Owner>::value, "can only copy from Foo<true> to Foo<false>");
    }

    template<bool U>
    Foo &operator=(const Foo<U> &)
    {
        static_assert(ok_to_copy_foos<Owner, Owner>::value, "can only assign from Foo<true> to Foo<false>");
        return *this;
    }

    void bar()
    {
        std::cout << owner_ << " \n";
    }
};

In this class the intent is that you can copy or assign but the result should always be a Foo<false> while everything else is prohibited. Essentially that means that you cannot copy or assign from Foo<true> to Foo`. I am not sure if there is any better way to achieve that but this is what I got at the moment.

However, there is something that will not work as I would like and I wanted some help in achieving that.

Foo<true> t;
auto f = t;

This will lead in compiler error so the question is can the compiler figure out that auto should actually be Foo<false> ?

Upvotes: 0

Views: 52

Answers (2)

einpoklum
einpoklum

Reputation: 132240

As @SamVarshavchik writes, auto won't do that for you. But I'd like to opine about how you might want to approach this differently:

I feel you're overusing templates here. Essentially, your Owner template argument is instance-specific data. Barring other fundamental considerations, it should be a data member of the Foo class. When that's the case, you will be able to easily have assignment operator force the assignee have owner be false. Now, it's true that this won't prevent you from being able to call methods which should not work - so you would throw runtime exceptions rather than compile-time asserts - but if that's of critical importance you can achieve the same effect with subclassing.

Also, it may well be worthwhile to simply have some sort of a proxy or facade class for your Foo, or perhaps just an iterator into it, which do not even have the interface for making copies.

With one or both of the above suggestions, you would not even need/want the trait class, since the class definitions and names would make it immediately obvious to both the compiler and the programmer reading the code what can be copied into what.

Upvotes: 0

Sam Varshavchik
Sam Varshavchik

Reputation: 118435

The short answer is: no. C++ simply does not work this way.

auto means: the object being declared is the same type as the expression that initializes it. If this results in a compilation error, the compiler isn't going to try every class it knows about, as an alternative, to see if maybe there's an available conversion that can be used to initialize it from the expression.

Upvotes: 1

Related Questions