2011-08-04 74 views
0

我有variant类。它有一对构造函数:模板类型扣除问题

/// Construct and fill. 
template <typename T> 
inline 
variant (const T& t) 
{ 
    YYASSERT (sizeof (T) <= S); 
    new (buffer.raw) T(t); 
} 

template <typename T> 
inline 
variant (T&& t) 
{ 
    YYASSERT (sizeof (T) <= S); 
    new (buffer.raw) T(std::move(t)); 
} 

现在,我已经叫这个代码的构造函数:

parser::symbol_type 
parser::make_IDENTIFIER (const Wide::ParsedFile::Identifier*& v) 
{ 
return symbol_type (token::IDENTIFIER, v); 
} 

symbol_type需要variant,因为它是在这个特定的构造第二个参数,v正在隐转换。

但是,MSVC将尝试使用右值引用构造函数而不是使用其他构造函数,导致在尝试引用new时出现编译错误。为什么是这样,我该如何让它停止?

+0

你有一个最小的,独立的例子吗? –

+0

@James:不幸的是,代码是由外部程序自动生成的,我对它并不特别熟悉,所以我不确定。 – Puppy

回答

3

您通常不应该使模板化的T&&函数超载。而应该有转发功能单一:

template <typename T> 
inline 
variant (T&& t) 
{ 
    typedef typename std::remove_reference<T>::type Tr; 
    YYASSERT (sizeof (Tr) <= S); 
    new (buffer.raw) Tr(std::forward<T>(t)); 
} 

这有你的两个重载的功能,同时避免选错一个问题。

我相信(不积极),这些都是在你的重载集合的两个变种:

varaint<const Wide::ParsedFile::Identifier*>(const Wide::ParsedFile::Identifier*const&) 
varaint<const Wide::ParsedFile::Identifier*&>(const Wide::ParsedFile::Identifier*&) 

,第二个胜利,因为它比第一(我在做一个猜测更加专业化,我不是100%正面)。

+0

这实际上并不能解决问题,因为T仍然是一个引用类型,并且构造仍然会失败。 – Puppy

+0

@DeadMG:我想你还需要一个'std :: remove_reference :: type'来放置新的类型(也许是'std :: remove_cv'?我不是100%确定的)。或者,如果您确实需要两次重载,则可以使用'enable_if'来禁止'T &&'重载被参考类型'T'实例化。 –

+0

是的,我认为你是正确的詹姆斯。编辑... –

0

第二个模板会更好地匹配,因为const说明符位于您的函数和第一个构造函数中的不同位置。

在第一个重载你将T与推导出

const Wide::ParsedFile::Identifier* 

,然后创建一个常量引用该类型。这增加了一个额外的常量。