Convertible templated math vector
I had to adjust your code style a bit before I could easily read the code. In particular:


Use InitialCaps for template parameters
Add a space before {
A newline after template&lt;...&gt; generally improves readability


Thus:

template&lt;class T, size_t Dimensions&gt;
struct vec {
    using coord_type = T;       
    static constexpr size_t dimension_count = Dimensions;

    std::array&lt;T, Dimensions&gt; coords;

    template&lt;class U&gt;
    operator vec&lt;U, Dimensions&gt;() const {
        std::array&lt;U, Dimensions&gt; casted_coords;
        std::transform(
            coords.begin(),
            coords.end(), 
            casted_coords.begin(),
            [](T coord) {
                return static_cast&lt;U&gt;(coord);
            }
        );
        return {casted_coords};
    }
};


Notice that I personally prefer to use the original template parameters T, Dimensions, etc. in places where your code used the member typedefs coord_type, dimension_count etc.; I find that this improves readability but I believe reasonable people may differ on the subject.

(In particular, the C++ Standard always uses member typedefs in declarations such as reference operator*() const as opposed to T&amp; operator*() const; but I think that's because the name reference is part of the API of the class, whereas the name T is given for exposition only. That's a Standard-ism that we don't necessarily need to emulate when writing our own code.)



Nit: Dimensions is technically the wrong name for a single dimension. Also, by capitalizing the template parameter, we've freed up the shorter name dimensions (or dimension) for the constexpr member variable. You never have to use a tediously long name like dimension_count if you manage your naming real estate effectively!



        return {casted_coords};


The extra braces here are a pessimization; they inhibit move-elision (a.k.a. Named Return Value Optimization). Remove them... oh wait, I see, casted_coords is a std::array, not a vec! Why are you constructing a separate array and then copying it into the vec? That seems pointless!

At the very least, this should be

return { std::move(casted_coords) };


but ideally you'd define casted_coords to be of type vec&lt;U, Dimensions&gt; and then transform the data straight into casted_coords.coords.begin().



            [](T coord) {
                return static_cast&lt;U&gt;(coord);
            }


This lambda takes its parameter by-copy, which is going to be expensive if T is, say, std::string. Prefer to take generic parameters by const&amp; or (in C++14) by perfect-forward:

            [](const T&amp; coord) {
                return static_cast&lt;U&gt;(coord);
            }

            [](auto&amp;&amp; coord) {
                return static_cast&lt;U&gt;(std::forward&lt;decltype(coord)&gt;(coord));
            }


In this case the former is better because it's less typing (and thus fewer chances to screw something up).



Your operator vec&lt;U, Dimensions&gt;() should be explicit, unless you have a darn good reason for it not to be. Most possible reasons I can think of do not qualify as "darn good."



In fact, I'd prefer to go further, and say that you shouldn't be using C++'s native "conversion" mechanisms for this kind of conversion at all. IMO you should write a user-defined function, along the lines of static_pointer_cast or any_cast, that does precisely and explicitly what you want.

template&lt;class To, class From, size_t Dim&gt;
auto static_vec_cast(const vec&lt;From, Dim&gt;&amp; from) -&gt; vec&lt;To, Dim&gt; {
    vec&lt;To, Dim&gt; to;
    std::transform(
        from.coords.begin(),
        from.coords.end(), 
        to.coords.begin(),
        [](const From&amp; x) {
            return static_cast&lt;To&gt;(x);
        }
    );
    return to;
}

int main() {
    vec&lt;int, 3&gt; a = {{1,2,3}};
    vec&lt;float, 3&gt; b = static_vec_cast&lt;float&gt;(a);
}


Season with SFINAE to taste.



However, this still has a major flaw: You're accidentally requiring that To be default-constructible! That's no good (especially if it does happen to be default-constructible but the default constructor is expensive). You can fix this issue, but it requires metaprogramming.

template&lt;class To, class From, size_t Dim, size_t... Is&gt;
auto static_vec_cast(const vec&lt;From, Dim&gt;&amp; from, std::index_sequence&lt;Is...&gt;) -&gt; vec&lt;To, Dim&gt; {
    vec&lt;To, Dim&gt; to = {{
        static_cast&lt;To&gt;(from.coords[Is])...
    }};
    return to;
}

template&lt;class To, class From, size_t Dim&gt;
auto static_vec_cast(const vec&lt;From, Dim&gt;&amp; from) -&gt; vec&lt;To, Dim&gt; {
    return static_vec_cast&lt;To&gt;(from, std::make_index_sequence&lt;Dim&gt;{});
}


The advantage of this approach is that it's hardly any more lines of code, but it's more correct, and it doesn't rely on running std::transform at runtime — it just generates the correct code directly inline.

Writing an efficient static_vec_cast&lt;U&gt;(vec&lt;T, Dim&gt;&amp;&amp;) is left as an exercise for the reader.