根据满足哪个概念决定实例化哪个模板

Decide which template to instantiate based on which concept is satisfied

假设我有两个概念:

struct Vector3 {float x; float y; float z;};

template<typename T> concept ImplementsMeshGetters = requires(T a, uint index)
{
    { a.Position(index) }->std::convertible_to<Vector3>;
};

template<typename T> concept HasMeshMemberArrays = requires(T a, uint index)
{
    { a.positions[index] }->std::convertible_to<Vector3>;
};

然后我创建了一个模板化的 class,它受以下任一约束:

template<typename MeshType>
requires(ImplementsMeshGetters<MeshType> || ImplementsMeshGetters<MeshType>)  
    class Mesh 
    {
           Vector3 GetPosition(uint i);
    };

我想要 3 个版本的函数 GetPosition 专门化,一个用于第一个概念,一个用于第二个概念,还有一个以防万一编译器不知何故混淆,抛出一个错误来提醒用户class 没有正确编译。

我试过这个:


template<ImplementsMeshGetters MeshType>
Eigen::Vector3f AnimationMesh<MeshType>::GetPosition(uint i)
{
    return mesh.Position(i);
};

template<HasMeshMemberArrays MeshType>
Eigen::Vector3f AnimationMesh<MeshType>::GetPosition(uint i)
{
    return mesh.positions[i];
}

template<> Eigen::Vector3f AnimationMesh<typename T>::GetPosition(uint i)
{
    Assert(
        false,
        "Somehow the mesh doesn't obey either of it's constraints. Your compiler "
        "is likely broken.");
    return {0, 0, 0};
}

但它没有编译,因为我正在重新定义相同的符号。

我可以这样做:

template<typename MeshType> Vector3 AnimationMesh<MeshType>::GetPosition(uint i)
{
    if constexpr(ImplementsMeshGetters<MeshType>)
    {  //
        return mesh.Position(i);
    }
    else if constexpr(HasMeshMemberArrays<MeshType>)
    {
        return mesh.positions[i];
    }
    else
        constexpr
        {
            Assert(
                false,
                "Somehow the mesh doesn't obey either of it's constraints. Your compiler "
                "is likely broken.");
            return {0, 0, 0};
        }
};

但这比我可以实例化模板要难看一些。

在 C++20 中你可以定义约束成员函数:

template <typename MeshType>
class Mesh {
public:
  Vector3 GetPosition(uint i) requires ImplementsMeshGetters<MeshType> {
    return mesh.Position(i);
  }
  Vector3 GetPosition(uint i) requires HasMeshMemberArrays<MeshType> {
    return mesh.positions[i];
  }
private:
  MeshType mesh;
};

Live demo

只要没有重叠(比如当某些 MeshType 满足两个约束时),这就会起作用。因此 if constexpr 解决方案可能更稳健,因为它明确定义了重叠情况下的优先级。

注意:您的尝试看起来像是显式成员特化,它不会起作用,因为要特化一个成员函数,所有封闭模板也必须完全特化。