防止模板参数上的 ADL

rkj*_*nsn 5 c++ templates

我目前有一个采用一系列类型的类模板。每种类型可能需要使用类本身进行实例化。我目前拥有的是这样的:

template <typename... Types>
struct TypeList; // Not defined

struct Placeholder; // Not defined

template <typename Types, typename AnotherType = Default>
class MyClass
{
    // ...
};
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
        Placeholder>, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
Run Code Online (Sandbox Code Playgroud)

MyClass将取代的外观Placeholder,使用结果类型,一切都很好。

当我尝试执行以下任一操作时,就会出现问题:

MyTypedef *my_ptr = &my_object;
my_free_function(my_object);
Run Code Online (Sandbox Code Playgroud)

这两者都会导致编译器错误,因为编译器尝试实例化Container1<Placeholder>Container2<std::string, Placeholder>执行参数相关查找(ADL),并且此实例化使用Placeholder, 本身的实例化失败。

我知道可以通过以下方式避免 ADL:

MyTypedef *my_ptr = std::addressof(my_object);
(my_free_function)(my_object);
Run Code Online (Sandbox Code Playgroud)

然而,我不想给用户带来MyClass必须不断抑制 ADL 的负担。是否有另一种直接的方法让用户提供类型列表而不将这些类型用于 ADL?

rkj*_*nsn 1

好的,我一切正常。诀窍是使用依赖类型而不是直接使用模板。我的最终解决方案是定义 TypeList 如下:

template <typename... Types>
struct TypeList
{
private:
    struct Holder
    {
    private:
        typedef TypeList<Types...> InnerTypeList;
        template <typename Types, typename AnotherType>
        friend class MyClass;
    };
public:
    typedef Holder type;
};
Run Code Online (Sandbox Code Playgroud)

然后,MyClass的用户可以做

typedef MyClass<TypeList<Container1<Placeholder>, Container2<std::string,
        Placeholder>::type, OtherType>, OptionalType> MyTypedef;
MyTypedef my_object;
Run Code Online (Sandbox Code Playgroud)

注意添加'::type'

最后,在 MyClass 中,我替换了

typedef typename SubstituteType<Types, Placeholder, MyClass>::type InternalTypeList;
Run Code Online (Sandbox Code Playgroud)

typedef typename SubstituteType<Types::InnerTypeList, Placeholder, MyClass>::type
        InternalTypeList;
Run Code Online (Sandbox Code Playgroud)

给我和以前一样的类型InternalTypeList

由于依赖类型Holder没有自己的模板参数,因此编译器不必出于 ADL 目的实例化占位符类型,并且一切正常。