期望一个类型,得到一个模板
Expected a type, got a template
我正在写一种 "asynchronous factory",其中耗时的具体对象构造被推迟到 std::async
任务。
每个 AsyncFactory
将存储一个指向对象的 smart 指针。
[这不是工厂模式最正确的应用,但它是为了MWE。
#include <future>
#include <memory>
#include <type_traits>
#include <cassert>
/**
* @param I is the interface type
* @param Ptr is the memory handler. Default = unique; optional = shared
*/
template <class I, template<class> class Ptr = std::unique_ptr>
class AsyncFactory
{
/**
* @param C - the concrete type for the interface I
* @param Ts - the variadic params
*/
template <class C, typename... Ts>
void _future_reload(Ts&&... params)
{
if (std::is_same<Ptr, std::unique_ptr>()) // line21
{
ptr = std::make_unique<C>(std::forward<Ts>(params)...);
}
else
{
if (std::is_same<Ptr, std::shared_ptr>()) // line27
{
ptr = std::make_shared<C>(std::forward<Ts>(params)...);
}
else
{
static_assert(0, "unacceptable type for smart pointer");// line33
}
}
}
public:
Ptr<I> ptr;
AsyncFactory() :
ptr(nullptr)
{}
/**
* @param C - the concrete type. Default: the interface type
* @param Ts - the variadic params
*/
template <class C = I, typename... Ts>
void reload(Ts&&... params)
{
std::future<void> fReload =
std::async(std::launch::async,
&AsyncFactory::_future_reload<C, Ts...>, this,
std::forward<Ts>(params)...);
}
};
class BaseVirtual
{
virtual void foo() = 0;
};
class DerivedConcrete :
public BaseVirtual
{
void foo() override {;}
};
int main()
{
AsyncFactory<BaseVirtual, std::shared_ptr> fac;
fac.reload<DerivedConcrete>();
}
智能指针出现问题。我必须为 unique
/shared
指针调用不同的 make
rs。但是 g++ -std=c++14
以
停止
f.cpp: In member function ‘void AsyncFactory<I, Ptr>::_future_reload(Ts&& ...)’:
f.cpp:21:44: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, class> struct std::is_same’
if (std::is_same<Ptr, std::unique_ptr>())
^
f.cpp:21:44: note: expected a type, got ‘Ptr’
f.cpp:21:44: error: type/value mismatch at argument 2 in template parameter list for ‘template<class, class> struct std::is_same’
f.cpp:21:44: note: expected a type, got ‘unique_ptr’
f.cpp:27:45: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, class> struct std::is_same’
if (std::is_same<Ptr, std::shared_ptr>())
^
f.cpp:27:45: note: expected a type, got ‘Ptr’
f.cpp:27:45: error: type/value mismatch at argument 2 in template parameter list for ‘template<class, class> struct std::is_same’
f.cpp:27:45: note: expected a type, got ‘shared_ptr’
f.cpp:33:9: error: static assertion failed: unacceptable type for smart pointer
static_assert(0, "unacceptable type for smart pointer");
std::unique_ptr
不是类型。 std::unique_ptr<int>
是一种类型。您需要传递显式模板参数才能在 is_same
.
中使用它
此外,您可能不想以这种方式使用 if
,因为无论 is_same
的结果如何,两个分支都需要有效。在 C++17 中,您将使用 if constexpr(...)
来解决此问题 - 在 C++14 中,您可以使用更传统的基于重载的方法或基于标记分派的方法。例如
auto impl(std::true_type /* is shared ptr */) { /* ... */ }
auto impl(std::false_type /* is unique ptr */) { /* ... */ }
用法:
ptr = impl(std::is_same<Ptr, std::shared_ptr<T>>{}, /* ... */);
你不能像这样比较模板模板参数,你只能比较具体类型std::is_same
。此外,您甚至不能再为 std::shared_ptr
和 std::unique_ptr
使用相同的 AsyncFactory
模板签名:https://godbolt.org/g/tNiYB1
您的问题的解决方案是引入另一层抽象:
struct UseUnique
{
template<class I>
using Ptr = std::unique_ptr<I>;
template<class C, typename... Ts>
static auto build(Ts&&... params)
{
return std::make_unique<C>(std::forward<Ts>(params)...);
}
};
struct UseShared
{
template<class I>
using Ptr = std::shared_ptr<I>;
template<class C, typename... Ts>
static auto build(Ts&&... params)
{
return std::make_shared<C>(std::forward<Ts>(params)...);
}
};
这些结构包含定义成员和构建具体类型所需的信息(即要使用的指针类型和 make_X
函数)。然后你可以这样做:
template <class I, class UseWhat = UseShared>
class AsyncFactory
{
template <class C, typename... Ts>
void _future_reload(Ts&&... params)
{
ptr = UseWhat::template build<C>(std::forward<Ts>(params)...);
}
public:
using Ptr = typename UseWhat::template Ptr<I>;
Ptr ptr;
// ...
}
因此
AsyncFactory<Interf, UseUnique> fac;
fac.reload<Concrete>();
完整的工作代码在这里:https://godbolt.org/g/L2511J
这些结构可能应该在一个单独的命名空间中,并且可能有更好的名称。作为练习留给 reader :)
我正在写一种 "asynchronous factory",其中耗时的具体对象构造被推迟到 std::async
任务。
每个 AsyncFactory
将存储一个指向对象的 smart 指针。
[这不是工厂模式最正确的应用,但它是为了MWE。
#include <future>
#include <memory>
#include <type_traits>
#include <cassert>
/**
* @param I is the interface type
* @param Ptr is the memory handler. Default = unique; optional = shared
*/
template <class I, template<class> class Ptr = std::unique_ptr>
class AsyncFactory
{
/**
* @param C - the concrete type for the interface I
* @param Ts - the variadic params
*/
template <class C, typename... Ts>
void _future_reload(Ts&&... params)
{
if (std::is_same<Ptr, std::unique_ptr>()) // line21
{
ptr = std::make_unique<C>(std::forward<Ts>(params)...);
}
else
{
if (std::is_same<Ptr, std::shared_ptr>()) // line27
{
ptr = std::make_shared<C>(std::forward<Ts>(params)...);
}
else
{
static_assert(0, "unacceptable type for smart pointer");// line33
}
}
}
public:
Ptr<I> ptr;
AsyncFactory() :
ptr(nullptr)
{}
/**
* @param C - the concrete type. Default: the interface type
* @param Ts - the variadic params
*/
template <class C = I, typename... Ts>
void reload(Ts&&... params)
{
std::future<void> fReload =
std::async(std::launch::async,
&AsyncFactory::_future_reload<C, Ts...>, this,
std::forward<Ts>(params)...);
}
};
class BaseVirtual
{
virtual void foo() = 0;
};
class DerivedConcrete :
public BaseVirtual
{
void foo() override {;}
};
int main()
{
AsyncFactory<BaseVirtual, std::shared_ptr> fac;
fac.reload<DerivedConcrete>();
}
智能指针出现问题。我必须为 unique
/shared
指针调用不同的 make
rs。但是 g++ -std=c++14
以
f.cpp: In member function ‘void AsyncFactory<I, Ptr>::_future_reload(Ts&& ...)’:
f.cpp:21:44: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, class> struct std::is_same’
if (std::is_same<Ptr, std::unique_ptr>())
^
f.cpp:21:44: note: expected a type, got ‘Ptr’
f.cpp:21:44: error: type/value mismatch at argument 2 in template parameter list for ‘template<class, class> struct std::is_same’
f.cpp:21:44: note: expected a type, got ‘unique_ptr’
f.cpp:27:45: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, class> struct std::is_same’
if (std::is_same<Ptr, std::shared_ptr>())
^
f.cpp:27:45: note: expected a type, got ‘Ptr’
f.cpp:27:45: error: type/value mismatch at argument 2 in template parameter list for ‘template<class, class> struct std::is_same’
f.cpp:27:45: note: expected a type, got ‘shared_ptr’
f.cpp:33:9: error: static assertion failed: unacceptable type for smart pointer
static_assert(0, "unacceptable type for smart pointer");
std::unique_ptr
不是类型。 std::unique_ptr<int>
是一种类型。您需要传递显式模板参数才能在 is_same
.
此外,您可能不想以这种方式使用 if
,因为无论 is_same
的结果如何,两个分支都需要有效。在 C++17 中,您将使用 if constexpr(...)
来解决此问题 - 在 C++14 中,您可以使用更传统的基于重载的方法或基于标记分派的方法。例如
auto impl(std::true_type /* is shared ptr */) { /* ... */ }
auto impl(std::false_type /* is unique ptr */) { /* ... */ }
用法:
ptr = impl(std::is_same<Ptr, std::shared_ptr<T>>{}, /* ... */);
你不能像这样比较模板模板参数,你只能比较具体类型std::is_same
。此外,您甚至不能再为 std::shared_ptr
和 std::unique_ptr
使用相同的 AsyncFactory
模板签名:https://godbolt.org/g/tNiYB1
您的问题的解决方案是引入另一层抽象:
struct UseUnique
{
template<class I>
using Ptr = std::unique_ptr<I>;
template<class C, typename... Ts>
static auto build(Ts&&... params)
{
return std::make_unique<C>(std::forward<Ts>(params)...);
}
};
struct UseShared
{
template<class I>
using Ptr = std::shared_ptr<I>;
template<class C, typename... Ts>
static auto build(Ts&&... params)
{
return std::make_shared<C>(std::forward<Ts>(params)...);
}
};
这些结构包含定义成员和构建具体类型所需的信息(即要使用的指针类型和 make_X
函数)。然后你可以这样做:
template <class I, class UseWhat = UseShared>
class AsyncFactory
{
template <class C, typename... Ts>
void _future_reload(Ts&&... params)
{
ptr = UseWhat::template build<C>(std::forward<Ts>(params)...);
}
public:
using Ptr = typename UseWhat::template Ptr<I>;
Ptr ptr;
// ...
}
因此
AsyncFactory<Interf, UseUnique> fac;
fac.reload<Concrete>();
完整的工作代码在这里:https://godbolt.org/g/L2511J
这些结构可能应该在一个单独的命名空间中,并且可能有更好的名称。作为练习留给 reader :)