diff --git a/CMakeLists.txt b/CMakeLists.txt
index 32b02e3d13c2c6f17f337bf9320d94fd7fb09fb0..ac362bcc2644c88886525723a2a392763a8b2459 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,3 +14,7 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
 add_library(typed-geometry STATIC ${SOURCES})
 
 target_include_directories(typed-geometry PUBLIC "src")
+
+if (CMAKE_CXX_STANDARD GREATER_EQUAL 17)
+    target_compile_definitions(typed-geometry PUBLIC TG_SUPPORT_CXX17)
+endif()
diff --git a/README.md b/README.md
index 4f2cf63701af3c4c87c13dc6df8296653278d400..a881025f95c8cf42d7b23ff8f7e86605d601576e 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,11 @@ TODO: splines
 * if still ambiguous: faster changing parameters go last (e.g. `coordinates(tri, point)` or `mix(a, b, t)`)
 
 
+### C++ 17 Features
+
+* deduction guides: `auto v = tg::vec(1.0f, 2.0f, 3.0f)`
+* structured binding: `auto [x, y, z] = tg::vec3(...)`
+
 ## Dependencies
 
 None.
@@ -79,4 +84,3 @@ None.
 * Benchmark how compile times are affected by includes / templates
 * Add tests that verify optimal assembly generated
 * Fractional and bigint data types
-* Deduction guides
diff --git a/src/tg/detail/functions/transpose.hh b/src/tg/detail/functions/transpose.hh
new file mode 100644
index 0000000000000000000000000000000000000000..95d97cf87acb350b9609a0f2e51a1eb88be7f3bc
--- /dev/null
+++ b/src/tg/detail/functions/transpose.hh
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "../../types/mat.hh"
+
+namespace tg
+{
+template <int C, int R, class T>
+constexpr mat<R, C, T> transpose(mat<C, R, T> const& m)
+{
+    mat<R, C, T> r;
+    for (auto y = 0; y < R; ++y)
+        for (auto x = 0; x < C; ++x)
+            r[y][x] = m[x][y];
+    return r;
+}
+} // namespace tg
diff --git a/src/tg/types/mat.hh b/src/tg/types/mat.hh
index 298f1bb7564ed8c6f49484166fe6e8bc442f1bdb..b5df679b0d9fd500f54b8678e4788ce89b4c523b 100644
--- a/src/tg/types/mat.hh
+++ b/src/tg/types/mat.hh
@@ -90,6 +90,20 @@ using umat4x4 = mat<4, 4, u32>;
 
 // ======== IMPLEMENTATION ========
 
+/*
+ * Memory layout of a 4x4:
+ *  0  4  8 12
+ *  1  5  9 13
+ *  2  6 10 14
+ *  3  7 11 15
+ *
+ * i.e. col-major
+ *
+ * matCxR (cols x rows)
+ *
+ * mat3x4 has no translational part
+ * mat4x3 has no projective part
+ */
 template <int C, int R, class ScalarT>
 struct mat
 {
@@ -97,8 +111,13 @@ struct mat
     using col_t = vec<R, ScalarT>;
     using transpose_t = mat<C, R, ScalarT>;
 
+    static constexpr shape<2> shape = make_shape(C, R);
+
     col_t m[R];
 
+    constexpr col_t& operator[](int i) { return m[i]; }
+    constexpr col_t const& operator[](int i) const { return m[i]; }
+
     mat() = default;
 };
 
diff --git a/src/tg/types/pos.hh b/src/tg/types/pos.hh
index 561618ac247d1190b622bcc9ce1e14e750649460..902f0432d3e82961e8ee19b9fae2fa4a34dcef4d 100644
--- a/src/tg/types/pos.hh
+++ b/src/tg/types/pos.hh
@@ -190,7 +190,20 @@ struct pos<4, ScalarT>
 template <class ScalarT>
 constexpr pos<4, ScalarT> pos<4, ScalarT>::zero = {ScalarT(0), ScalarT(0), ScalarT(0), ScalarT(0)};
 
+// comparison operators
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(pos, pos, bool, operator==, &&, ==);
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(pos, pos, bool, operator!=, ||, !=);
 
+// deduction guides
+#ifdef TG_SUPPORT_CXX17
+template <class T>
+pos(T const& x)->pos<1, T>;
+template <class T>
+pos(T const& x, T const& y)->pos<2, T>;
+template <class T>
+pos(T const& x, T const& y, T const& z)->pos<3, T>;
+template <class T>
+pos(T const& x, T const& y, T const& z, T const& w)->pos<4, T>;
+#endif
+
 } // namespace tg
diff --git a/src/tg/types/size.hh b/src/tg/types/size.hh
index 0cb7c408ef8b614a156226f7d2c9792c5d11126c..73660808d872e75ad520ed332720708e0f33330c 100644
--- a/src/tg/types/size.hh
+++ b/src/tg/types/size.hh
@@ -167,6 +167,19 @@ struct size<4, ScalarT>
     }
 };
 
+// comparison operators
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(size, size, bool, operator==, &&, ==);
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(size, size, bool, operator!=, ||, !=);
+
+// deduction guides
+#ifdef TG_SUPPORT_CXX17
+template <class T>
+size(T const& x)->size<1, T>;
+template <class T>
+size(T const& x, T const& y)->size<2, T>;
+template <class T>
+size(T const& x, T const& y, T const& z)->size<3, T>;
+template <class T>
+size(T const& x, T const& y, T const& z, T const& w)->size<4, T>;
+#endif
 } // namespace tg
diff --git a/src/tg/types/vec.hh b/src/tg/types/vec.hh
index 2b8b7bb7abbd056f98cc29d9d02ed8c8f4eb9e31..a9e7a07c2b049e4e58139b79ed783a25fbf0ad45 100644
--- a/src/tg/types/vec.hh
+++ b/src/tg/types/vec.hh
@@ -307,7 +307,20 @@ constexpr vec<4, ScalarT> vec<4, ScalarT>::unit_z = {ScalarT(0), ScalarT(0), Sca
 template <class ScalarT>
 constexpr vec<4, ScalarT> vec<4, ScalarT>::unit_w = {ScalarT(0), ScalarT(0), ScalarT(0), ScalarT(1)};
 
+// comparison operators
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(vec, vec, bool, operator==, &&, ==);
 TG_IMPL_DEFINE_REDUCTION_OP_BINARY(vec, vec, bool, operator!=, ||, !=);
 
+// deduction guides
+#ifdef TG_SUPPORT_CXX17
+template <class T>
+vec(T const& x)->vec<1, T>;
+template <class T>
+vec(T const& x, T const& y)->vec<2, T>;
+template <class T>
+vec(T const& x, T const& y, T const& z)->vec<3, T>;
+template <class T>
+vec(T const& x, T const& y, T const& z, T const& w)->vec<4, T>;
+#endif
+
 } // namespace tg