expanded canon() to have better template argument handling