Use one argument for template parameter deduction?

Using two type parameters is probably the best option, but if you really want to perform deduction only from the first argument, simply make the second non-deducible:

template<typename T>
void assign( T* a, typename std::identity<T>::type b );
  • Demo: http://ideone.com/ZW6Mpu

An earlier version of this answer suggested using the template alias feature introduced in C++11. But template aliases are still a deducible context. The primary reason that std::identity and std::remove_reference prevents deduction is that template classes can be specialized, so even if you have a typedef of a template type parameter, it's possible that another specialization has a typedef of the same type. Because of the possible ambiguity, deduction doesn't take place. But template aliases preclude specialization, and so deduction still occurs.


The problem is that the compiler is deducing conflicting information from the first and the second argument. From the first argument, it deduces T to be double (i is a double); from the second one, it deduces T to be int (the type of 2 is int).

You have two main possibilities here:

  • Always be explicit about the type of your arguments:

    assign(&i, 2.0);
    //         ^^^^
    
  • Or let your function template accept two template parameters:

    template <typename T, typename U> 
    void assign(T *a, U b) { *a = b; }
    

    In this case, you may want to SFINAE-constraint the template so that it does not partecipate to overload resolution in case U is not convertible to T:

    #include <type_traits>
    
    template <typename T, typename U,
        typename std::enable_if<
            std::is_convertible<U, T>::value>::type* = nullptr>
    void assign(T *a, U b) { *a = b; }
    

    If you do not need to exclude your function from the overload set when U is not convertible to T, you may want to have a static assertion inside assign() to produce a nicer compilation error:

    #include <type_traits>
    
    template<typename T, typename U>
    void assign(T *a, U b)
    {
        static_assert(std::is_convertible<T, U>::value,
            "Error: Source type not convertible to destination type.");
    
        *a = b;
    }
    

It's just that the value 2 is deduced to the type int, which doesn't match the template parameter deduced by &i. You need to use the value as a double:

assign(&i, 2.0);